diff --git a/src/bin/parser_test.rs b/src/bin/parser_test.rs index f065829ba..74a484849 100755 --- a/src/bin/parser_test.rs +++ b/src/bin/parser_test.rs @@ -1,35 +1,35 @@ -use std::{env, fs, io}; -use std::fs::File; -use regex::Regex; -use std::io::{BufRead, BufReader}; -use std::path::PathBuf; use gosub_engine::html5_parser::input_stream::InputStream; use gosub_engine::html5_parser::node::NodeData; -use gosub_engine::html5_parser::parser::Html5Parser; use gosub_engine::html5_parser::parser::document::Document; +use gosub_engine::html5_parser::parser::Html5Parser; +use regex::Regex; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::PathBuf; +use std::{env, fs, io}; -pub struct TestResults{ - tests: usize, // Number of tests (as defined in the suite) - assertions: usize, // Number of assertions (different combinations of input/output per test) - succeeded: usize, // How many succeeded assertions - failed: usize, // How many failed assertions - failed_position: usize, // How many failed assertions where position is not correct +pub struct TestResults { + tests: usize, // Number of tests (as defined in the suite) + assertions: usize, // Number of assertions (different combinations of input/output per test) + succeeded: usize, // How many succeeded assertions + failed: usize, // How many failed assertions + failed_position: usize, // How many failed assertions where position is not correct } struct Test { - file_path: String, // Filename of the test - line: usize, // Line number of the test - data: String, // input stream - errors: Vec, // errors - document: Vec, // document tree - document_fragment: Vec, // fragment + file_path: String, // Filename of the test + line: usize, // Line number of the test + data: String, // input stream + errors: Vec, // errors + document: Vec, // document tree + document_fragment: Vec, // fragment } -fn main () -> io::Result<()> { +fn main() -> io::Result<()> { let default_dir = "./html5lib-tests"; let dir = env::args().nth(1).unwrap_or(default_dir.to_string()); - let mut results = TestResults{ + let mut results = TestResults { tests: 0, assertions: 0, succeeded: 0, @@ -41,7 +41,7 @@ fn main () -> io::Result<()> { let entry = entry?; let path = entry.path(); - if ! path.ends_with("tests1.dat") { + if !path.ends_with("tests1.dat") { continue; } @@ -85,10 +85,13 @@ fn read_tests(file_path: PathBuf) -> io::Result> { let line = line?; if line.starts_with("#data") { - if !current_test.data.is_empty() || !current_test.errors.is_empty() || !current_test.document.is_empty() { + if !current_test.data.is_empty() + || !current_test.errors.is_empty() + || !current_test.document.is_empty() + { current_test.data = current_test.data.trim_end().to_string(); tests.push(current_test); - current_test = Test{ + current_test = Test { file_path: file_path.to_str().unwrap().clone().to_string(), line: line_num, data: "".to_string(), @@ -114,9 +117,9 @@ fn read_tests(file_path: PathBuf) -> io::Result> { let col = caps.name("col").unwrap().as_str().parse::().unwrap(); let code = caps.name("code").unwrap().as_str().to_string(); - current_test.errors.push(Error{ code, line, col }); + current_test.errors.push(Error { code, line, col }); } - }, + } "document" => current_test.document.push(line), "document_fragment" => current_test.document_fragment.push(line), _ => (), @@ -125,7 +128,10 @@ fn read_tests(file_path: PathBuf) -> io::Result> { } // Push the last test if it has data - if !current_test.data.is_empty() || !current_test.errors.is_empty() || !current_test.document.is_empty() { + if !current_test.data.is_empty() + || !current_test.errors.is_empty() + || !current_test.document.is_empty() + { current_test.data = current_test.data.trim_end().to_string(); tests.push(current_test); } @@ -133,8 +139,11 @@ fn read_tests(file_path: PathBuf) -> io::Result> { Ok(tests) } -fn run_tree_test(test_idx: usize,test: &Test, results: &mut TestResults) { - println!("๐Ÿงช Running test #{}: {}::{}", test_idx, test.file_path, test.line); +fn run_tree_test(test_idx: usize, test: &Test, results: &mut TestResults) { + println!( + "๐Ÿงช Running test #{}: {}::{}", + test_idx, test.file_path, test.line + ); results.tests += 1; @@ -155,7 +164,11 @@ fn run_tree_test(test_idx: usize,test: &Test, results: &mut TestResults) { } if parse_errors.len() != test.errors.len() { - println!("โŒ Unexpected errors found (wanted {}, got {}): ", test.errors.len(), parse_errors.len()); + println!( + "โŒ Unexpected errors found (wanted {}, got {}): ", + test.errors.len(), + parse_errors.len() + ); // for want_err in &test.errors { // println!(" * Want: '{}' at {}:{}", want_err.code, want_err.line, want_err.col); // } @@ -165,7 +178,7 @@ fn run_tree_test(test_idx: usize,test: &Test, results: &mut TestResults) { // results.assertions += 1; // results.failed += 1; } else { - println!("โœ… Found {} errors", parse_errors.len()); + println!("โœ… Found {} errors", parse_errors.len()); } // // // Check each error messages @@ -204,7 +217,6 @@ fn run_tree_test(test_idx: usize,test: &Test, results: &mut TestResults) { // idx += 1; // } - if old_failed != results.failed { println!("----------------------------------------"); println!("๐Ÿ“„ Input stream: "); @@ -226,9 +238,9 @@ fn run_tree_test(test_idx: usize,test: &Test, results: &mut TestResults) { #[derive(PartialEq)] enum ErrorResult { - Success, // Found the correct error - Failure, // Didn't find the error (not even with incorrect position) - PositionFailure, // Found the error, but on an incorrect position + Success, // Found the correct error + Failure, // Didn't find the error (not even with incorrect position) + PositionFailure, // Found the error, but on an incorrect position } #[derive(PartialEq)] @@ -242,27 +254,39 @@ fn match_document_tree(document: &Document, expected: &Vec) -> bool { match_node(0, -1, -1, document, expected).is_some() } -fn match_node(node_idx: usize, expected_id: isize, indent: isize, document: &Document, expected: &Vec) -> Option { +fn match_node( + node_idx: usize, + expected_id: isize, + indent: isize, + document: &Document, + expected: &Vec, +) -> Option { let node = document.get_node_by_id(node_idx).unwrap(); if node_idx > 0 { match &node.data { NodeData::Element { name, .. } => { let value = format!("|{}<{}>", " ".repeat((indent as usize * 2) + 1), name); - if value != expected[expected_id as usize] { - println!("โŒ {}, Found unexpected element node: {}", expected[expected_id as usize], name); + if value != expected[expected_id as usize] { + println!( + "โŒ {}, Found unexpected element node: {}", + expected[expected_id as usize], name + ); return None; } else { - println!("โœ… {}", expected[expected_id as usize]); + println!("โœ… {}", expected[expected_id as usize]); } } NodeData::Text { value } => { - let value = format!("|{}\"{}\"", " ".repeat(indent as usize * 2 + 1), value); + let value = format!("|{}\"{}\"", " ".repeat(indent as usize * 2 + 1), value); if value != expected[expected_id as usize] { - println!("โŒ {}, Found unexpected text node: {}", expected[expected_id as usize], value); + println!( + "โŒ {}, Found unexpected text node: {}", + expected[expected_id as usize], value + ); return None; } else { - println!("โœ… {}", expected[expected_id as usize]); + println!("โœ… {}", expected[expected_id as usize]); } } _ => {} @@ -272,7 +296,9 @@ fn match_node(node_idx: usize, expected_id: isize, indent: isize, document: &Doc let mut next_expected_idx = expected_id + 1; for &child_idx in &node.children { - if let Some(new_idx) = match_node(child_idx, next_expected_idx, indent + 1, document, expected) { + if let Some(new_idx) = + match_node(child_idx, next_expected_idx, indent + 1, document, expected) + { next_expected_idx = new_idx as isize; } else { return None; @@ -286,17 +312,26 @@ fn match_node(node_idx: usize, expected_id: isize, indent: isize, document: &Doc fn match_error(got_err: &Error, expected_err: &Error) -> ErrorResult { if got_err == expected_err { // Found an exact match - println!("โœ… Found parse error '{}' at {}:{}", got_err.code, got_err.line, got_err.col); + println!( + "โœ… Found parse error '{}' at {}:{}", + got_err.code, got_err.line, got_err.col + ); return ErrorResult::Success; } if got_err.code != expected_err.code { - println!("โŒ Expected error '{}' at {}:{}", expected_err.code, expected_err.line, expected_err.col); + println!( + "โŒ Expected error '{}' at {}:{}", + expected_err.code, expected_err.line, expected_err.col + ); return ErrorResult::Failure; } // Found an error with the same code, but different line/pos - println!("โš ๏ธ Unexpected error position '{}' at {}:{} (got: {}:{})", expected_err.code, expected_err.line, expected_err.col, got_err.line, got_err.col); + println!( + "โš ๏ธ Unexpected error position '{}' at {}:{} (got: {}:{})", + expected_err.code, expected_err.line, expected_err.col, got_err.line, got_err.col + ); ErrorResult::PositionFailure -} \ No newline at end of file +} diff --git a/src/html5_parser/node.rs b/src/html5_parser/node.rs index 36f0239a2..9e2b7a836 100644 --- a/src/html5_parser/node.rs +++ b/src/html5_parser/node.rs @@ -46,9 +46,7 @@ impl Node { // This will only compare against the tag, namespace and attributes. Both nodes could still have // other parents and children. pub fn matches_tag_and_attrs(&self, other: &Self) -> bool { - self.name == other.name && - self.namespace == other.namespace && - self.data == other.data + self.name == other.name && self.namespace == other.namespace && self.data == other.data } } diff --git a/src/html5_parser/parser/adoption_agency.rs b/src/html5_parser/parser/adoption_agency.rs index b14d7ed94..38bda1546 100755 --- a/src/html5_parser/parser/adoption_agency.rs +++ b/src/html5_parser/parser/adoption_agency.rs @@ -17,7 +17,12 @@ impl<'a> Html5Parser<'a> { // Step 2 let current_node_id = current_node!(self).id; - if current_node!(self).name == *subject && ! self.active_formatting_elements.iter().any(|elem| elem == &ActiveElement::NodeId(current_node_id)) { + if current_node!(self).name == *subject + && !self + .active_formatting_elements + .iter() + .any(|elem| elem == &ActiveElement::NodeId(current_node_id)) + { self.open_elements.pop(); return; } @@ -77,7 +82,9 @@ impl<'a> Html5Parser<'a> { } // Step 4.5 - if open_elements_has!(self, formatting_element_name) && ! self.is_in_scope(&formatting_element_name, Scope::Regular) { + if open_elements_has!(self, formatting_element_name) + && !self.is_in_scope(&formatting_element_name, Scope::Regular) + { self.parse_error("formatting element not in scope"); return; } @@ -95,7 +102,7 @@ impl<'a> Html5Parser<'a> { for idx in (0..formatting_element_idx).rev() { match self.active_formatting_elements[idx] { - ActiveElement::Marker => {}, + ActiveElement::Marker => {} ActiveElement::NodeId(node_id) => { let node = self.document.get_node_by_id(node_id).unwrap(); if node.is_special() { @@ -162,12 +169,19 @@ impl<'a> Html5Parser<'a> { } // Step 4.13.4 - if inner_loop_counter > ADOPTION_AGENCY_INNER_LOOP_DEPTH && self.active_formatting_elements.contains(&ActiveElement::NodeId(node_id)) { + if inner_loop_counter > ADOPTION_AGENCY_INNER_LOOP_DEPTH + && self + .active_formatting_elements + .contains(&ActiveElement::NodeId(node_id)) + { self.active_formatting_elements.remove(node_idx); } // Step 4.13.5 - if ! self.active_formatting_elements.contains(&ActiveElement::NodeId(node_id)) { + if !self + .active_formatting_elements + .contains(&ActiveElement::NodeId(node_id)) + { // We have removed the node from the given node_idx self.open_elements.remove(node_idx); continue; @@ -210,8 +224,10 @@ impl<'a> Html5Parser<'a> { let new_element_id = self.document.add_node(new_element, furthest_block_id); // Step 4.18 - self.active_formatting_elements.remove(formatting_element_idx); - self.active_formatting_elements.insert(bookmark, ActiveElement::NodeId(new_element_id)); + self.active_formatting_elements + .remove(formatting_element_idx); + self.active_formatting_elements + .insert(bookmark, ActiveElement::NodeId(new_element_id)); // Step 4.19 // Remove formatting element from the stack of open elements, and insert the new element into the stack of open elements immediately below the position of furthest block in that stack. diff --git a/src/html5_parser/parser/mod.rs b/src/html5_parser/parser/mod.rs index febfe4e55..be330f4e1 100644 --- a/src/html5_parser/parser/mod.rs +++ b/src/html5_parser/parser/mod.rs @@ -121,7 +121,9 @@ macro_rules! pop_until_any { // Remove the given node_id from the open elements stack macro_rules! open_elements_remove { ($self:expr, $target_node_id: expr) => { - $self.open_elements.retain(|&node_id| node_id != $target_node_id); + $self + .open_elements + .retain(|&node_id| node_id != $target_node_id); }; } @@ -222,7 +224,6 @@ impl ActiveElement { } } - // The main parser object pub struct Html5Parser<'a> { tokenizer: Tokenizer<'a>, // tokenizer object @@ -242,9 +243,9 @@ pub struct Html5Parser<'a> { pending_table_character_tokens: Vec, // Pending table character tokens ack_self_closing: bool, // Acknowledge self closing tags active_formatting_elements: Vec, // List of active formatting elements or markers - is_fragment_case: bool, // Is the current parsing a fragment case - document: Document, // A reference to the document we are parsing - error_logger: Rc>, // Error logger, which is shared with the tokenizer + is_fragment_case: bool, // Is the current parsing a fragment case + document: Document, // A reference to the document we are parsing + error_logger: Rc>, // Error logger, which is shared with the tokenizer } // Defines the scopes for in_scope() @@ -901,9 +902,11 @@ impl<'a> Html5Parser<'a> { self.insertion_mode = InsertionMode::InRow; self.reprocess_token = true; - }, - Token::StartTagToken { name, .. } if name == "tbody" || name == "tfoot" || name == "thead" => { - if ! self.is_in_scope(name, Scope::Table) { + } + Token::StartTagToken { name, .. } + if name == "tbody" || name == "tfoot" || name == "thead" => + { + if !self.is_in_scope(name, Scope::Table) { self.parse_error("tbody, tfoot or thead tag not allowed in in table body insertion mode"); // ignore token continue; @@ -913,9 +916,15 @@ impl<'a> Html5Parser<'a> { self.open_elements.pop(); self.insertion_mode = InsertionMode::InTable; - }, - Token::StartTagToken { name, .. } if ["caption", "col", "colgroup", "tbody", "tfoot", "thead"].contains(&name.as_str()) => { - if ! self.is_in_scope("tbody", Scope::Table) && ! self.is_in_scope("tfoot", Scope::Table) && ! self.is_in_scope("thead", Scope::Table) { + } + Token::StartTagToken { name, .. } + if ["caption", "col", "colgroup", "tbody", "tfoot", "thead"] + .contains(&name.as_str()) => + { + if !self.is_in_scope("tbody", Scope::Table) + && !self.is_in_scope("tfoot", Scope::Table) + && !self.is_in_scope("thead", Scope::Table) + { self.parse_error("caption, col, colgroup, tbody, tfoot or thead tag not allowed in in table body insertion mode"); // ignore token continue; @@ -928,7 +937,10 @@ impl<'a> Html5Parser<'a> { self.reprocess_token = true; } Token::EndTagToken { name, .. } if name == "table" => { - if ! self.is_in_scope("tbody", Scope::Table) && ! self.is_in_scope("tfoot", Scope::Table) && ! self.is_in_scope("thead", Scope::Table) { + if !self.is_in_scope("tbody", Scope::Table) + && !self.is_in_scope("tfoot", Scope::Table) + && !self.is_in_scope("thead", Scope::Table) + { self.parse_error("caption, col, colgroup, tbody, tfoot or thead tag not allowed in in table body insertion mode"); continue; } @@ -963,9 +975,9 @@ impl<'a> Html5Parser<'a> { self.insertion_mode = InsertionMode::InCell; self.active_formatting_elements_push_marker(); - }, + } Token::EndTagToken { name, .. } if name == "tr" => { - if ! self.is_in_scope("tr", Scope::Table) { + if !self.is_in_scope("tr", Scope::Table) { self.parse_error("tr tag not allowed in in row insertion mode"); // ignore token continue; @@ -976,8 +988,13 @@ impl<'a> Html5Parser<'a> { self.insertion_mode = InsertionMode::InTableBody; } - Token::StartTagToken { name, .. } if ["caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr"].contains(&name.as_str()) => { - if ! self.is_in_scope("tr", Scope::Table) { + Token::StartTagToken { name, .. } + if [ + "caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr", + ] + .contains(&name.as_str()) => + { + if !self.is_in_scope("tr", Scope::Table) { self.parse_error("caption, col, colgroup, tbody, tfoot or thead tag not allowed in in row insertion mode"); // ignore token continue; @@ -990,7 +1007,7 @@ impl<'a> Html5Parser<'a> { self.reprocess_token = true; } Token::EndTagToken { name, .. } if name == "table" => { - if ! self.is_in_scope("tr", Scope::Table) { + if !self.is_in_scope("tr", Scope::Table) { self.parse_error("table tag not allowed in in row insertion mode"); // ignore token continue; @@ -1002,14 +1019,16 @@ impl<'a> Html5Parser<'a> { self.insertion_mode = InsertionMode::InTableBody; self.reprocess_token = true; } - Token::EndTagToken { name, .. } if name == "tbody" || name == "tfoot" || name == "thead" => { - if ! self.is_in_scope(name, Scope::Table) { + Token::EndTagToken { name, .. } + if name == "tbody" || name == "tfoot" || name == "thead" => + { + if !self.is_in_scope(name, Scope::Table) { self.parse_error("tbody, tfoot or thead tag not allowed in in table body insertion mode"); // ignore token continue; } - if ! self.is_in_scope("tr", Scope::Table) { + if !self.is_in_scope("tr", Scope::Table) { // ignore token continue; } @@ -1042,8 +1061,10 @@ impl<'a> Html5Parser<'a> { Token::StartTagToken { name, .. } if name == "th" || name == "td" => { let token_name = name.clone(); - if ! self.is_in_scope(name.as_str(), Scope::Table) { - self.parse_error("th or td tag not allowed in in cell insertion mode"); + if !self.is_in_scope(name.as_str(), Scope::Table) { + self.parse_error( + "th or td tag not allowed in in cell insertion mode", + ); // ignore token continue; } @@ -1059,9 +1080,17 @@ impl<'a> Html5Parser<'a> { self.active_formatting_elements_clear_until_marker(); self.insertion_mode = InsertionMode::InRow; - }, - Token::StartTagToken { name, .. } if ["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"].contains(&name.as_str()) => { - if ! self.is_in_scope("td", Scope::Table) && ! self.is_in_scope("th", Scope::Table) { + } + Token::StartTagToken { name, .. } + if [ + "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", + "thead", "tr", + ] + .contains(&name.as_str()) => + { + if !self.is_in_scope("td", Scope::Table) + && !self.is_in_scope("th", Scope::Table) + { self.parse_error("caption, col, colgroup, tbody, tfoot or thead tag not allowed in in cell insertion mode"); // ignore token (fragment case?) continue; @@ -1080,8 +1109,14 @@ impl<'a> Html5Parser<'a> { self.parse_error("end tag not allowed in in cell insertion mode"); // ignore token } - Token::EndTagToken { name, .. } if name == "table" || name == "tbody" || name == "tfoot" || name == "thead" || name == "tr" => { - if ! self.is_in_scope(name.as_str(), Scope::Table) { + Token::EndTagToken { name, .. } + if name == "table" + || name == "tbody" + || name == "tfoot" + || name == "thead" + || name == "tr" => + { + if !self.is_in_scope(name.as_str(), Scope::Table) { self.parse_error("tbody, tfoot or thead tag not allowed in in table body insertion mode"); // ignore token continue; @@ -1185,7 +1220,9 @@ impl<'a> Html5Parser<'a> { } Token::EndTagToken { name, .. } if name == "select" => { if !self.is_in_scope("select", Scope::Select) { - self.parse_error("select end tag not allowed in in select insertion mode"); + self.parse_error( + "select end tag not allowed in in select insertion mode", + ); // ignore token continue; } @@ -1764,7 +1801,9 @@ impl<'a> Html5Parser<'a> { // Pop all elements back to a table context fn clear_stack_back_to_table_body_context(&mut self) { while !self.open_elements.is_empty() { - if ["tbody", "tfoot", "thead", "template", "html"].contains(¤t_node!(self).name.as_str()) { + if ["tbody", "tfoot", "thead", "template", "html"] + .contains(¤t_node!(self).name.as_str()) + { return; } self.open_elements.pop(); @@ -1942,7 +1981,7 @@ impl<'a> Html5Parser<'a> { // Add attributes to body element // @TODO add body attributes - }, + } Token::StartTagToken { name, .. } if name == "frameset" => { self.parse_error("frameset tag not allowed in in body insertion mode"); @@ -1996,26 +2035,59 @@ impl<'a> Html5Parser<'a> { self.insertion_mode = InsertionMode::AfterBody; self.reprocess_token = true; - }, - Token::StartTagToken { name, .. } if name == "address" || name == "article" || name == "aside" || name == "blockquote" || name == "center" || name == "details" || name == "dialog" || name == "dir" || name == "div" || name == "dl" || name == "fieldset" || name == "figcaption" || name == "figure" || name == "footer" || name == "header" || name == "hgroup" || name == "main" || name == "menu" || name == "nav" || name == "ol" || name == "p" || name == "section" || name == "summary" || name == "ul" => { + } + Token::StartTagToken { name, .. } + if name == "address" + || name == "article" + || name == "aside" + || name == "blockquote" + || name == "center" + || name == "details" + || name == "dialog" + || name == "dir" + || name == "div" + || name == "dl" + || name == "fieldset" + || name == "figcaption" + || name == "figure" + || name == "footer" + || name == "header" + || name == "hgroup" + || name == "main" + || name == "menu" + || name == "nav" + || name == "ol" + || name == "p" + || name == "section" + || name == "summary" + || name == "ul" => + { if self.is_in_scope("p", Scope::Button) { self.close_p_element(); } self.insert_html_element(&self.current_token.clone()); - }, - Token::StartTagToken { name, .. } if name == "h1" || name == "h2" || name == "h3" || name == "h4" || name == "h5" || name == "h6" => { + } + Token::StartTagToken { name, .. } + if name == "h1" + || name == "h2" + || name == "h3" + || name == "h4" + || name == "h5" + || name == "h6" => + { if self.is_in_scope("p", Scope::Button) { self.close_p_element(); } - if ["h1", "h2", "h3", "h4", "h5", "h6"].contains(¤t_node!(self).name.as_str()) { + if ["h1", "h2", "h3", "h4", "h5", "h6"].contains(¤t_node!(self).name.as_str()) + { self.parse_error("h1-h6 not allowed in in body insertion mode"); self.open_elements.pop(); } self.insert_html_element(&self.current_token.clone()); - }, + } Token::StartTagToken { name, .. } if name == "pre" || name == "listing" => { if self.is_in_scope("p", Scope::Button) { self.close_p_element(); @@ -2044,10 +2116,8 @@ impl<'a> Html5Parser<'a> { self.form_element = Some(node_id); } } - Token::StartTagToken { name, .. } if name == "li" => { - } - Token::StartTagToken { name, .. } if name == "dd" || name == "dt" => { - } + Token::StartTagToken { name, .. } if name == "li" => {} + Token::StartTagToken { name, .. } if name == "dd" || name == "dt" => {} Token::StartTagToken { name, .. } if name == "plaintext" => { if self.is_in_scope("p", Scope::Button) { self.close_p_element(); @@ -2068,8 +2138,35 @@ impl<'a> Html5Parser<'a> { self.insert_html_element(&self.current_token.clone()); self.frameset_ok = false; } - Token::EndTagToken { name, .. } if name == "address" || name == "article" || name == "aside" || name == "blockquote" || name == "button" || name == "center" || name == "details" || name == "dialog" || name == "dir" || name == "div" || name == "dl" || name == "fieldset" || name == "figcaption" || name == "figure" || name == "footer" || name == "header" || name == "hgroup" || name == "listing" || name == "main" || name == "menu" || name == "nav" || name == "ol" || name == "pre" || name == "section" || name == "summary" || name == "ul" => { - if ! self.is_in_scope(name, Scope::Regular) { + Token::EndTagToken { name, .. } + if name == "address" + || name == "article" + || name == "aside" + || name == "blockquote" + || name == "button" + || name == "center" + || name == "details" + || name == "dialog" + || name == "dir" + || name == "div" + || name == "dl" + || name == "fieldset" + || name == "figcaption" + || name == "figure" + || name == "footer" + || name == "header" + || name == "hgroup" + || name == "listing" + || name == "main" + || name == "menu" + || name == "nav" + || name == "ol" + || name == "pre" + || name == "section" + || name == "summary" + || name == "ul" => + { + if !self.is_in_scope(name, Scope::Regular) { self.parse_error("end tag not in scope"); // ignore token return; @@ -2107,7 +2204,7 @@ impl<'a> Html5Parser<'a> { self.parse_error("end tag not at top of stack"); } } else { - if ! self.is_in_scope(name, Scope::Regular) { + if !self.is_in_scope(name, Scope::Regular) { self.parse_error("end tag not in scope"); // ignore token return; @@ -2124,7 +2221,7 @@ impl<'a> Html5Parser<'a> { } } Token::EndTagToken { name, .. } if name == "p" => { - if ! self.is_in_scope(name, Scope::Button) { + if !self.is_in_scope(name, Scope::Button) { self.parse_error("end tag not in scope"); self.insert_html_element(&self.current_token.clone()); @@ -2135,7 +2232,7 @@ impl<'a> Html5Parser<'a> { self.close_p_element(); } Token::EndTagToken { name, .. } if name == "li" => { - if ! self.is_in_scope(name, Scope::ListItem) { + if !self.is_in_scope(name, Scope::ListItem) { self.parse_error("end tag not in scope"); // ignore token return; @@ -2150,7 +2247,7 @@ impl<'a> Html5Parser<'a> { pop_until!(self, *name); } Token::EndTagToken { name, .. } if name == "dd" || name == "dt" => { - if ! self.is_in_scope(name, Scope::Regular) { + if !self.is_in_scope(name, Scope::Regular) { self.parse_error("end tag not in scope"); // ignore token return; @@ -2164,13 +2261,21 @@ impl<'a> Html5Parser<'a> { pop_until!(self, *name); } - Token::EndTagToken { name, .. } if name == "h1" || name == "h2" || name == "h3" || name == "h4" || name == "h5" || name == "h6" => { - if ! self.is_in_scope("h1", Scope::Regular) || - ! self.is_in_scope("h2", Scope::Regular) || - ! self.is_in_scope("h3", Scope::Regular) || - ! self.is_in_scope("h4", Scope::Regular) || - ! self.is_in_scope("h5", Scope::Regular) || - ! self.is_in_scope("h6", Scope::Regular) { + Token::EndTagToken { name, .. } + if name == "h1" + || name == "h2" + || name == "h3" + || name == "h4" + || name == "h5" + || name == "h6" => + { + if !self.is_in_scope("h1", Scope::Regular) + || !self.is_in_scope("h2", Scope::Regular) + || !self.is_in_scope("h3", Scope::Regular) + || !self.is_in_scope("h4", Scope::Regular) + || !self.is_in_scope("h5", Scope::Regular) + || !self.is_in_scope("h6", Scope::Regular) + { self.parse_error("end tag not in scope"); // ignore token return; @@ -2262,8 +2367,10 @@ impl<'a> Html5Parser<'a> { self.active_formatting_elements_push_marker(); self.frameset_ok = false; } - Token::EndTagToken { name, .. } if name == "applet" || name == "marquee" || name == "object" => { - if ! self.is_in_scope(name, Scope::Regular) { + Token::EndTagToken { name, .. } + if name == "applet" || name == "marquee" || name == "object" => + { + if !self.is_in_scope(name, Scope::Regular) { self.parse_error("end tag not in scope"); // ignore token return; @@ -2279,7 +2386,9 @@ impl<'a> Html5Parser<'a> { self.active_formatting_elements_clear_until_marker(); } Token::StartTagToken { name, .. } if name == "table" => { - if self.document.quirks_mode != QuirksMode::Quirks && self.is_in_scope("p", Scope::Button) { + if self.document.quirks_mode != QuirksMode::Quirks + && self.is_in_scope("p", Scope::Button) + { self.close_p_element(); } @@ -2358,7 +2467,11 @@ impl<'a> Html5Parser<'a> { acknowledge_closing_tag!(self, *is_self_closing); } - Token::StartTagToken { name, is_self_closing, .. } if name == "hr" => { + Token::StartTagToken { + name, + is_self_closing, + .. + } if name == "hr" => { if self.is_in_scope("p", Scope::Button) { self.close_p_element(); } @@ -2865,30 +2978,34 @@ impl<'a> Html5Parser<'a> { // Remove the given node_id from the active formatting elements list fn active_formatting_elements_remove(&mut self, target_node_id: usize) { - self.active_formatting_elements.retain(|node_id| { - match node_id { - ActiveElement::NodeId(node_id) => { - *node_id != target_node_id - }, + self.active_formatting_elements + .retain(|node_id| match node_id { + ActiveElement::NodeId(node_id) => *node_id != target_node_id, _ => true, - } - }); + }); } // Push a node onto the active formatting stack, make sure only max 3 of them can be added (between markers) fn active_formatting_elements_push(&mut self, node_id: usize) { let mut idx = self.active_formatting_elements.len(); if idx == 0 { - self.active_formatting_elements.push(ActiveElement::NodeId(node_id)); + self.active_formatting_elements + .push(ActiveElement::NodeId(node_id)); return; } // Fetch the node we want to push, so we can compare - let element_node = self.document.get_node_by_id(node_id).expect("node id not found"); + let element_node = self + .document + .get_node_by_id(node_id) + .expect("node id not found"); let mut found = 0; loop { - let active_elem = *self.active_formatting_elements.get(idx - 1).expect("index out of bounds"); + let active_elem = *self + .active_formatting_elements + .get(idx - 1) + .expect("index out of bounds"); if let ActiveElement::Marker = active_elem { // Don't continue after the last marker break; @@ -2896,7 +3013,10 @@ impl<'a> Html5Parser<'a> { // Fetch the node we want to compare with let match_node = match active_elem { - ActiveElement::NodeId(node_id) => self.document.get_node_by_id(node_id).expect("node id not found"), + ActiveElement::NodeId(node_id) => self + .document + .get_node_by_id(node_id) + .expect("node id not found"), ActiveElement::Marker => unreachable!(), }; if match_node.matches_tag_and_attrs(element_node) { @@ -2915,7 +3035,8 @@ impl<'a> Html5Parser<'a> { idx -= 1; } - self.active_formatting_elements.push(ActiveElement::NodeId(node_id)); + self.active_formatting_elements + .push(ActiveElement::NodeId(node_id)); } fn reconstruct_formatting(&mut self) { @@ -2931,7 +3052,10 @@ impl<'a> Html5Parser<'a> { return; } - if self.open_elements.contains(&entry.node_id().expect("node id not found")) { + if self + .open_elements + .contains(&entry.node_id().expect("node id not found")) + { return; } @@ -2943,7 +3067,10 @@ impl<'a> Html5Parser<'a> { break; } - if self.open_elements.contains(&entry.node_id().expect("node id not found")) { + if self + .open_elements + .contains(&entry.node_id().expect("node id not found")) + { break; } @@ -2958,7 +3085,11 @@ impl<'a> Html5Parser<'a> { let entry = self.active_formatting_elements[entry_index]; let node_id = entry.node_id().expect("node id not found"); - let entry_node = self.document.get_node_by_id(node_id).expect("node not found").clone(); + let entry_node = self + .document + .get_node_by_id(node_id) + .expect("node not found") + .clone(); let new_node_id = self.clone_node(entry_node); self.active_formatting_elements[entry_index] = ActiveElement::NodeId(new_node_id); @@ -3176,4 +3307,4 @@ impl<'a> Html5Parser<'a> { println!("{}", self.document); println!("-----------------------------"); } -} \ No newline at end of file +}