From 81871a07b481422c6e0462ada47668c829fca105 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 10:27:29 +0300 Subject: [PATCH 01/25] working on it --- html5ever/examples/print-tree-actions.rs | 4 +- html5ever/src/tree_builder/mod.rs | 56 +++++++++--- markup5ever/Cargo.toml | 3 + markup5ever/interface/tree_builder.rs | 48 ++++++++++- xml5ever/src/serialize/mod.rs | 2 +- xml5ever/src/tree_builder/mod.rs | 105 +++++++++++++++++------ 6 files changed, 180 insertions(+), 38 deletions(-) diff --git a/html5ever/examples/print-tree-actions.rs b/html5ever/examples/print-tree-actions.rs index 7ac2de17..29c74755 100644 --- a/html5ever/examples/print-tree-actions.rs +++ b/html5ever/examples/print-tree-actions.rs @@ -17,6 +17,7 @@ use std::io; use html5ever::parse_document; use html5ever::tendril::*; +use html5ever::tree_builder::TreeBuilder; use html5ever::tree_builder::{ AppendNode, AppendText, ElementFlags, NodeOrText, QuirksMode, TreeSink, }; @@ -154,8 +155,9 @@ impl TreeSink for Sink { println!("Set current line to {}", line_number); } - fn pop(&mut self, elem: &usize) { + fn pop(&mut self, elem: &usize) -> Result<(), SuperfluousClosingElement> { println!("Popped element {}", elem); + Ok(()) } } diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 5d392dbb..205ee4b1 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -11,6 +11,8 @@ //! The HTML5 tree builder. +use markup5ever::interface::tree_builder::SuperfluousClosingElement; + pub use crate::interface::{create_element, ElementFlags, NextParserState, Tracer, TreeSink}; pub use crate::interface::{AppendNode, AppendText, Attribute, NodeOrText}; pub use crate::interface::{LimitedQuirks, NoQuirks, Quirks, QuirksMode}; @@ -643,8 +645,31 @@ where } //§ END - fn current_node(&self) -> &Handle { - self.open_elems.last().expect("no current element") + /// Indicate that a node was popped off the stack of open elements. + #[cfg(api_v2)] + fn current_node(&mut self, node: &Self::Handle) -> Option<&Handle> { + self.current_node_v2(node) + } + + /// Indicate that a node was popped off the stack of open elements. + #[cfg(not(api_v2))] + #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + fn current_node(&mut self, node: &Handle) -> &Handle { + self.current_node_unconditional(node) + } + + /// Like pop(), but in the case of no open element, just warn instead of returning an error. + fn current_node_unconditional(&mut self, node: &Handle) -> &Handle { + let current = self.current_node(node); + if self.current_node_v2(node).is_none() { + warn!("no current element"); + } + current + } + + /// Note: Don't use this function, use pop() with api_v2 feature instead. + fn current_node_v2(&mut self, node: &Self::Handle) -> Option<&Handle> { + self.open_elems.last(node) } fn adjusted_current_node(&self) -> &Handle { @@ -660,7 +685,7 @@ where where TagSet: Fn(ExpandedName) -> bool, { - set(self.sink.elem_name(self.current_node())) + set(self.sink.elem_name(self.current_node_unconditional())) // FIXME: Is using `current_node_unconditional()` correct? } // Insert at the "appropriate place for inserting a node". @@ -673,10 +698,10 @@ where // 1. if self.current_node_named(subject.clone()) { if self - .position_in_active_formatting(self.current_node()) + .position_in_active_formatting(self.current_node_unconditional()) // FIXME: Is using `current_node_unconditional()` correct? .is_none() { - self.pop(); + self.pop_unconditional(); // FIXME: Is using `current_node_unconditional()` correct? return; } } @@ -719,7 +744,7 @@ where } // 8. - if !self.sink.same_node(self.current_node(), &fmt_elem) { + if !self.sink.same_node(self.current_node_unconditional(), &fmt_elem) { // FIXME: Is using `current_node_unconditional()` correct? self.sink .parse_error(Borrowed("Formatting element not current node")); } @@ -879,10 +904,21 @@ where self.open_elems.push(elem.clone()); } - fn pop(&mut self) -> Handle { - let elem = self.open_elems.pop().expect("no current element"); - self.sink.pop(&elem); - elem + fn pop_v2(&mut self) -> Result { + if let Some(elem) = self.open_elems.pop() { + self.sink.pop(&elem); + Ok(elem) + } else { + Err(SuperfluousClosingElement::new()) + } + } + + fn pop_unconditional(&mut self) -> Handle { + if let Ok(result) = self.pop_v2() { + result + } else { + panic!("no current element"); + } } fn remove_from_stack(&mut self, elem: &Handle) { diff --git a/markup5ever/Cargo.toml b/markup5ever/Cargo.toml index edcc0ba7..da3019ee 100644 --- a/markup5ever/Cargo.toml +++ b/markup5ever/Cargo.toml @@ -22,3 +22,6 @@ log = "0.4" [build-dependencies] string_cache_codegen = "0.5.1" phf_codegen = "0.9" + +[features] +api_v2 = [] diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index 43361f36..ba009db4 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -11,6 +11,7 @@ //! //! It can be used by a parser to create the DOM graph structure in memory. +use log::warn; use crate::interface::{Attribute, ExpandedName, QualName}; use std::borrow::Cow; use tendril::StrTendril; @@ -75,6 +76,27 @@ pub struct ElementFlags { _private: (), } +#[derive(Debug)] +pub enum TreeBuilderError { + WronglyClosed(SuperfluousClosingElement), +} + +// TODO: Error message. +#[derive(Debug)] +pub struct SuperfluousClosingElement {} + +impl SuperfluousClosingElement { + pub fn new() -> Self { + Self { } + } +} + +impl From for TreeBuilderError { + fn from(value: SuperfluousClosingElement) -> Self { + Self::WronglyClosed(value) + } +} + /// A constructor for an element. /// /// # Examples @@ -185,7 +207,31 @@ pub trait TreeSink { fn mark_script_already_started(&mut self, _node: &Self::Handle) {} /// Indicate that a node was popped off the stack of open elements. - fn pop(&mut self, _node: &Self::Handle) {} + #[cfg(api_v2)] + fn pop(&mut self, _node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { + self.pop_v2(node) + } + + /// Indicate that a node was popped off the stack of open elements. + #[cfg(not(api_v2))] + #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + fn pop(&mut self, node: &Self::Handle) { + self.pop_unconditional(node) + } + + /// Like pop(), but in the case of no open element, just warn instead of returning an error. + fn pop_unconditional(&mut self, node: &Self::Handle) { + if self.pop_v2(node).is_err() { + warn!("no current element"); + }; + } + + /// Indicate that a node was popped off the stack of open elements. + /// + /// Note: Don't use this function, use pop() with api_v2 feature instead. + fn pop_v2(&mut self, _node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { + Ok(()) + } /// Get a handle to a template's template contents. The tree builder /// promises this will never be called with something else than diff --git a/xml5ever/src/serialize/mod.rs b/xml5ever/src/serialize/mod.rs index 182ed9c8..84251a3b 100644 --- a/xml5ever/src/serialize/mod.rs +++ b/xml5ever/src/serialize/mod.rs @@ -60,7 +60,7 @@ impl NamespaceMapStack { } fn pop(&mut self) { - self.0.pop(); + self.0.pop().expect("no such element"); } } diff --git a/xml5ever/src/tree_builder/mod.rs b/xml5ever/src/tree_builder/mod.rs index 708776d0..832c46dd 100644 --- a/xml5ever/src/tree_builder/mod.rs +++ b/xml5ever/src/tree_builder/mod.rs @@ -11,7 +11,7 @@ mod types; use log::{debug, warn}; use mac::{_tt_as_expr_hack, matches, unwrap_or_return}; -use markup5ever::{local_name, namespace_prefix, namespace_url, ns}; +use markup5ever::{local_name, namespace_prefix, namespace_url, ns, interface::tree_builder::SuperfluousClosingElement}; use std::borrow::Cow; use std::borrow::Cow::Borrowed; use std::collections::btree_map::Iter; @@ -53,8 +53,8 @@ impl NamespaceMapStack { } #[doc(hidden)] - pub fn pop(&mut self) { - self.0.pop(); + pub fn pop_v2(&mut self) -> Option { + self.0.pop() } } @@ -428,7 +428,7 @@ where fn end(&mut self) { for node in self.open_elems.drain(..).rev() { - self.sink.pop(&node); + self.sink.pop_unconditional(&node); // It may give multiple warnings. Maybe better to produce just a single warning. } } @@ -437,8 +437,29 @@ where } } -fn current_node(open_elems: &[Handle]) -> &Handle { - open_elems.last().expect("no current element") +/// Indicate that a node was popped off the stack of open elements. +#[cfg(api_v2)] +fn current_node(open_elems: &[Handle]) -> Option<&Handle> { + current_node_v2(open_elems) +} + +// /// Indicate that a node was popped off the stack of open elements. +// #[cfg(not(api_v2))] +// #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] +// fn current_node(open_elems: &[Handle]) -> &Handle { +// current_node_unconditional(open_elems) +// } + +/// Like pop(), but in the case of no open element, just warn instead of returning an error. +fn current_node_unconditional(open_elems: &[Handle]) -> &Handle { + current_node_v2(open_elems).expect("no current element") +} + +/// Indicate that a node was popped off the stack of open elements. +/// +/// Note: Don't use this function, use pop() with api_v2 feature instead. +fn current_node_v2(open_elems: &[Handle]) -> Option<&Handle> { + open_elems.last() } #[doc(hidden)] @@ -447,12 +468,16 @@ where Handle: Clone, Sink: TreeSink, { - fn current_node(&self) -> &Handle { - self.open_elems.last().expect("no current element") + fn current_node_v2(&self) -> Option<&Handle> { + self.open_elems.last() + } + + fn current_node_unconditional(&self) -> &Handle { + self.current_node_v2().expect("no current element") } fn insert_appropriately(&mut self, child: NodeOrText) { - let target = current_node(&self.open_elems); + let target = current_node_unconditional(&self.open_elems); // FIXME: Is using `current_node_unconditional()` correct? self.sink.append(target, child); } @@ -465,7 +490,7 @@ where fn append_tag(&mut self, tag: Tag) -> XmlProcessResult { let child = create_element(&mut self.sink, tag.name, tag.attrs); self.insert_appropriately(AppendNode(child.clone())); - self.sink.pop(&child); + self.sink.pop_unconditional(&child); // FIXME: This may be an error: Does the element necessarily exist? Done } @@ -490,7 +515,7 @@ where } fn append_comment_to_tag(&mut self, text: StrTendril) -> XmlProcessResult { - let target = current_node(&self.open_elems); + let target = current_node_unconditional(&self.open_elems); // FIXME: Is using `current_node_unconditional()` correct? let comment = self.sink.create_comment(text); self.sink.append(target, AppendNode(comment)); Done @@ -518,7 +543,7 @@ where } fn append_pi_to_tag(&mut self, pi: Pi) -> XmlProcessResult { - let target = current_node(&self.open_elems); + let target = current_node_unconditional(&self.open_elems); // FIXME: Is using `current_node_unconditional()` correct? let pi = self.sink.create_pi(pi.target, pi.data); self.sink.append(target, AppendNode(pi)); Done @@ -545,26 +570,27 @@ where if self.current_node_in(|x| pred(x)) { break; } - self.pop(); + self.pop_unconditional(); } } + // FIXME: Is using `current_node_unconditional()` correct? fn current_node_in(&self, set: TagSet) -> bool where TagSet: Fn(ExpandedName) -> bool, { // FIXME: take namespace into consideration: - set(self.sink.elem_name(self.current_node())) + set(self.sink.elem_name(self.current_node_unconditional())) } fn close_tag(&mut self, tag: Tag) -> XmlProcessResult { debug!( "Close tag: current_node.name {:?} \n Current tag {:?}", - self.sink.elem_name(self.current_node()), + self.sink.elem_name(self.current_node_unconditional()), &tag.name ); - if *self.sink.elem_name(self.current_node()).local != tag.name.local { + if *self.sink.elem_name(self.current_node_unconditional()).local != tag.name.local { self.sink .parse_error(Borrowed("Current node doesn't match tag")); } @@ -573,7 +599,7 @@ where if is_closed { self.pop_until(|p| p == tag.name.expanded()); - self.pop(); + self.pop_unconditional(); // FIXME: May this erroneously panic? } Done @@ -583,11 +609,39 @@ where self.open_elems.is_empty() } - fn pop(&mut self) -> Handle { - self.namespace_stack.pop(); - let node = self.open_elems.pop().expect("no current element"); - self.sink.pop(&node); - node + #[cfg(api_v2)] + fn pop(&mut self) -> Result { + self.pop_v2() + } + + // #[cfg(not(api_v2))] + // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + // fn pop(&mut self) -> Handle { + // self.pop_unconditional() + // } + + /// Like pop(), but in the case of no open element, just warn instead of returning an error. + fn pop_unconditional(&mut self) -> Handle { + if let Ok(result) = self.pop_v2() { + result + } else { + panic!("no current element"); + } + } + + /// Indicate that a node was popped off the stack of open elements. + /// + /// Note: Don't use this function, use pop() with api_v2 feature instead. + fn pop_v2(&mut self) -> Result { + if self.namespace_stack.pop_v2().is_none() { + return Err(SuperfluousClosingElement::new()) + } + if let Some(node) = self.open_elems.pop() { + self.sink.pop_v2(&node)?; + Ok(node) + } else { + Err(SuperfluousClosingElement::new()) + } } fn stop_parsing(&mut self) -> XmlProcessResult { @@ -595,8 +649,9 @@ where Done } + // FIMXE: Is using `current_node_unconditional()` correct? fn complete_script(&mut self) { - let current = current_node(&self.open_elems); + let current = current_node_unconditional(&self.open_elems); if self.sink.complete_script(current) == NextParserState::Suspend { self.next_tokenizer_state = Some(Quiescent); } @@ -653,7 +708,7 @@ where }; self.phase = EndPhase; let handle = self.append_tag_to_doc(tag); - self.sink.pop(&handle); + self.sink.pop_v2(&handle).unwrap(); Done }, CommentToken(comment) => self.append_comment_to_doc(comment), @@ -738,7 +793,7 @@ where retval }, TagToken(Tag { kind: ShortTag, .. }) => { - self.pop(); + self.pop_unconditional(); // FIXME: May this erroneously panic? if self.no_open_elems() { self.phase = EndPhase; } From 9c3659482be7cf7bf21438a956958cefb762da6d Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 10:48:50 +0300 Subject: [PATCH 02/25] working on it --- html5ever/src/tree_builder/mod.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 205ee4b1..3c2564b9 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -647,29 +647,29 @@ where /// Indicate that a node was popped off the stack of open elements. #[cfg(api_v2)] - fn current_node(&mut self, node: &Self::Handle) -> Option<&Handle> { - self.current_node_v2(node) + fn current_node(&self) -> Option<&Handle> { + self.current_node_v2() } /// Indicate that a node was popped off the stack of open elements. #[cfg(not(api_v2))] #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] - fn current_node(&mut self, node: &Handle) -> &Handle { - self.current_node_unconditional(node) + fn current_node(&self) -> &Handle { + self.current_node_unconditional() } /// Like pop(), but in the case of no open element, just warn instead of returning an error. - fn current_node_unconditional(&mut self, node: &Handle) -> &Handle { - let current = self.current_node(node); - if self.current_node_v2(node).is_none() { + fn current_node_unconditional(&self) -> &Handle { + let current = self.current_node(); + if self.current_node_v2().is_none() { warn!("no current element"); } current } /// Note: Don't use this function, use pop() with api_v2 feature instead. - fn current_node_v2(&mut self, node: &Self::Handle) -> Option<&Handle> { - self.open_elems.last(node) + fn current_node_v2(&self) -> Option<&Handle> { + self.open_elems.last() } fn adjusted_current_node(&self) -> &Handle { From 30827cea263e696793ee7665166849b03e45dc43 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 11:06:52 +0300 Subject: [PATCH 03/25] before using old API in new --- html5ever/src/tree_builder/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 3c2564b9..bcecf322 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -913,11 +913,9 @@ where } } - fn pop_unconditional(&mut self) -> Handle { - if let Ok(result) = self.pop_v2() { - result - } else { - panic!("no current element"); + fn pop_unconditional(&mut self) { + if self.pop_v2().is_err() { + warn!("no current element"); } } @@ -1091,7 +1089,7 @@ where return; } } - self.pop(); + self.pop_unconditional(); } } @@ -1701,13 +1699,13 @@ where if self.is_fragment() { self.foreign_start_tag(tag) } else { - self.pop(); + self.pop_unconditional(); while !self.current_node_in(|n| { *n.ns == ns!(html) || mathml_text_integration_point(n) || svg_html_integration_point(n) }) { - self.pop(); + self.pop_unconditional(); } ReprocessForeign(TagToken(tag)) } From 3cd2ffdce4704eefb1d1377c5360817058f7fa2b Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 11:50:07 +0300 Subject: [PATCH 04/25] before using old API in new --- html5ever/src/tree_builder/mod.rs | 11 ++++++-- html5ever/src/tree_builder/rules.rs | 36 +++++++++++++-------------- markup5ever/interface/tree_builder.rs | 12 ++++++--- xml5ever/src/tree_builder/mod.rs | 31 ++++++++++++++++------- 4 files changed, 57 insertions(+), 33 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index bcecf322..8eccb381 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -655,10 +655,11 @@ where #[cfg(not(api_v2))] #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn current_node(&self) -> &Handle { - self.current_node_unconditional() + self.open_elems.last().expect("no current node") } - /// Like pop(), but in the case of no open element, just warn instead of returning an error. + #[cfg(api_v2)] + /// Like current_node(), but in the case of no open element, just warn instead of returning an error. fn current_node_unconditional(&self) -> &Handle { let current = self.current_node(); if self.current_node_v2().is_none() { @@ -667,6 +668,12 @@ where current } + #[cfg(not(api_v2))] + /// Like current_node(), but in the case of no open element, just warn instead of returning an error. + fn current_node_unconditional(&self) -> &Handle { + self.current_node() + } + /// Note: Don't use this function, use pop() with api_v2 feature instead. fn current_node_v2(&self) -> Option<&Handle> { self.open_elems.last() diff --git a/html5ever/src/tree_builder/rules.rs b/html5ever/src/tree_builder/rules.rs index d9a4ba1f..3ec1bd9d 100644 --- a/html5ever/src/tree_builder/rules.rs +++ b/html5ever/src/tree_builder/rules.rs @@ -138,7 +138,7 @@ where } => { - self.pop(); + self.pop_unconditional(); self.mode = AfterHead; Done } @@ -171,7 +171,7 @@ where tag @ => self.unexpected(&tag), token => { - self.pop(); + self.pop_unconditional(); Reprocess(AfterHead, token) } }), @@ -181,7 +181,7 @@ where => self.step(InBody, token), => { - self.pop(); + self.pop_unconditional(); self.mode = InHead; Done }, @@ -201,7 +201,7 @@ where token => { self.unexpected(&token); - self.pop(); + self.pop_unconditional(); Reprocess(InHead, token) }, }), @@ -353,7 +353,7 @@ where self.close_p_element_in_button_scope(); if self.current_node_in(heading_tag) { self.sink.parse_error(Borrowed("nested heading tags")); - self.pop(); + self.pop_unconditional(); } self.insert_element_for(tag); Done @@ -666,7 +666,7 @@ where tag @ => { if self.current_node_named(local_name!("option")) { - self.pop(); + self.pop_unconditional(); } if self.current_node_named(local_name!("optgroup")) { - self.pop(); + self.pop_unconditional(); } self.insert_element_for(tag); Done @@ -1120,10 +1120,10 @@ where && self.current_node_named(local_name!("option")) && self.html_elem_named(&self.open_elems[self.open_elems.len() - 2], local_name!("optgroup")) { - self.pop(); + self.pop_unconditional(); } if self.current_node_named(local_name!("optgroup")) { - self.pop(); + self.pop_unconditional(); } else { self.unexpected(&token); } @@ -1132,7 +1132,7 @@ where => { if self.current_node_named(local_name!("option")) { - self.pop(); + self.pop_unconditional(); } else { self.unexpected(&token); } @@ -1289,7 +1289,7 @@ where if self.open_elems.len() == 1 { self.unexpected(&token); } else { - self.pop(); + self.pop_unconditional(); if !self.is_fragment() && !self.current_node_named(local_name!("frameset")) { self.mode = AfterFrameset; } diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index ba009db4..c3e8aac3 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -11,7 +11,6 @@ //! //! It can be used by a parser to create the DOM graph structure in memory. -use log::warn; use crate::interface::{Attribute, ExpandedName, QualName}; use std::borrow::Cow; use tendril::StrTendril; @@ -215,10 +214,9 @@ pub trait TreeSink { /// Indicate that a node was popped off the stack of open elements. #[cfg(not(api_v2))] #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] - fn pop(&mut self, node: &Self::Handle) { - self.pop_unconditional(node) - } + fn pop(&mut self, _node: &Self::Handle) {} + #[cfg(api_v2)] /// Like pop(), but in the case of no open element, just warn instead of returning an error. fn pop_unconditional(&mut self, node: &Self::Handle) { if self.pop_v2(node).is_err() { @@ -226,6 +224,12 @@ pub trait TreeSink { }; } + #[cfg(not(api_v2))] + /// Like pop(), but in the case of no open element, just warn instead of returning an error. + fn pop_unconditional(&mut self, node: &Self::Handle) { + self.pop(node) + } + /// Indicate that a node was popped off the stack of open elements. /// /// Note: Don't use this function, use pop() with api_v2 feature instead. diff --git a/xml5ever/src/tree_builder/mod.rs b/xml5ever/src/tree_builder/mod.rs index 832c46dd..b0814bce 100644 --- a/xml5ever/src/tree_builder/mod.rs +++ b/xml5ever/src/tree_builder/mod.rs @@ -438,10 +438,10 @@ where } /// Indicate that a node was popped off the stack of open elements. -#[cfg(api_v2)] -fn current_node(open_elems: &[Handle]) -> Option<&Handle> { - current_node_v2(open_elems) -} +// #[cfg(api_v2)] +// fn current_node(open_elems: &[Handle]) -> Option<&Handle> { +// current_node_v2(open_elems) +// } // /// Indicate that a node was popped off the stack of open elements. // #[cfg(not(api_v2))] @@ -614,6 +614,15 @@ where self.pop_v2() } + #[cfg(not(api_v2))] + fn pop(&mut self) -> Handle { + if let Ok(result) = self.pop_v2() { + result + } else { + panic!("no current element"); + } + } + // #[cfg(not(api_v2))] // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] // fn pop(&mut self) -> Handle { @@ -621,14 +630,18 @@ where // } /// Like pop(), but in the case of no open element, just warn instead of returning an error. - fn pop_unconditional(&mut self) -> Handle { - if let Ok(result) = self.pop_v2() { - result - } else { - panic!("no current element"); + #[cfg(api_v2)] + fn pop_unconditional(&mut self) { + if self.pop_v2().is_err() { + warn!("no current element"); } } + #[cfg(not(api_v2))] + fn pop_unconditional(&mut self) -> Handle { + self.pop() + } + /// Indicate that a node was popped off the stack of open elements. /// /// Note: Don't use this function, use pop() with api_v2 feature instead. From 50a6fed5f4295f073cfed259001c83ee38ba84c8 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 11:58:28 +0300 Subject: [PATCH 05/25] almost ready --- html5ever/src/tree_builder/rules.rs | 34 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/html5ever/src/tree_builder/rules.rs b/html5ever/src/tree_builder/rules.rs index 3ec1bd9d..c7f0c4ca 100644 --- a/html5ever/src/tree_builder/rules.rs +++ b/html5ever/src/tree_builder/rules.rs @@ -740,10 +740,11 @@ where } tag @ => { - let node = self.pop(); - self.mode = self.orig_mode.take().unwrap(); - if tag.name == local_name!("script") { - return Script(node); + if let Ok(node) = self.pop_v2() { + self.mode = self.orig_mode.take().unwrap(); + if tag.name == local_name!("script") { + return Script(node); + } } Done } @@ -1009,9 +1010,10 @@ where => { if self.in_scope_named(table_scope, local_name!("tr")) { self.pop_until_current(table_row_context); - let node = self.pop(); - self.assert_named(&node, local_name!("tr")); - self.mode = InTableBody; + if let Ok(node) = self.pop_v2() { + self.assert_named(&node, local_name!("tr")); + self.mode = InTableBody; + } } else { self.unexpected(&token); } @@ -1021,9 +1023,12 @@ where => { if self.in_scope_named(table_scope, local_name!("tr")) { self.pop_until_current(table_row_context); - let node = self.pop(); - self.assert_named(&node, local_name!("tr")); - Reprocess(InTableBody, token) + if let Ok(node) = self.pop_v2() { + self.assert_named(&node, local_name!("tr")); + Reprocess(InTableBody, token) + } else { + self.unexpected(&token) + } } else { self.unexpected(&token) } @@ -1033,9 +1038,12 @@ where if self.in_scope_named(table_scope, tag.name.clone()) { if self.in_scope_named(table_scope, local_name!("tr")) { self.pop_until_current(table_row_context); - let node = self.pop(); - self.assert_named(&node, local_name!("tr")); - Reprocess(InTableBody, TagToken(tag)) + if let Ok(node) = self.pop_v2() { + self.assert_named(&node, local_name!("tr")); + Reprocess(InTableBody, TagToken(tag)) + } else { + Done + } } else { Done } From 834577370dd7f445a3c167a6c340da44632567c4 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 11:58:46 +0300 Subject: [PATCH 06/25] almost ready --- markup5ever/interface/tree_builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index c3e8aac3..891f44c5 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -213,7 +213,6 @@ pub trait TreeSink { /// Indicate that a node was popped off the stack of open elements. #[cfg(not(api_v2))] - #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn pop(&mut self, _node: &Self::Handle) {} #[cfg(api_v2)] From 48e54b85a465d904535fdea613c732dad201c275 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 12:01:56 +0300 Subject: [PATCH 07/25] "prelease" of PR for testing --- markup5ever/interface/tree_builder.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index 891f44c5..ea02e0ed 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -213,6 +213,7 @@ pub trait TreeSink { /// Indicate that a node was popped off the stack of open elements. #[cfg(not(api_v2))] + #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn pop(&mut self, _node: &Self::Handle) {} #[cfg(api_v2)] @@ -226,6 +227,7 @@ pub trait TreeSink { #[cfg(not(api_v2))] /// Like pop(), but in the case of no open element, just warn instead of returning an error. fn pop_unconditional(&mut self, node: &Self::Handle) { + #[allow(deprecated)] self.pop(node) } From 0abb104a2ec0536e6971590ebf6dae74bf76cc99 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 12:09:38 +0300 Subject: [PATCH 08/25] code quickly reviewed --- html5ever/src/tree_builder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 8eccb381..5a4190d2 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -655,7 +655,7 @@ where #[cfg(not(api_v2))] #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn current_node(&self) -> &Handle { - self.open_elems.last().expect("no current node") + self.open_elems.last().expect("no current element") } #[cfg(api_v2)] From faa5c133301084f4c9939eb0659836e93858bd8a Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 12:15:24 +0300 Subject: [PATCH 09/25] note in Cargo.toml --- markup5ever/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/markup5ever/Cargo.toml b/markup5ever/Cargo.toml index da3019ee..83bcc75e 100644 --- a/markup5ever/Cargo.toml +++ b/markup5ever/Cargo.toml @@ -24,4 +24,5 @@ string_cache_codegen = "0.5.1" phf_codegen = "0.9" [features] +# Always use this feature in new code. In the future it will become the default. api_v2 = [] From 9637d89dcd8f62c94698f35dd7acfd23e7757479 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 12:26:15 +0300 Subject: [PATCH 10/25] no(api_v2) tests passed --- html5ever/examples/print-tree-actions.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/html5ever/examples/print-tree-actions.rs b/html5ever/examples/print-tree-actions.rs index 29c74755..bd280669 100644 --- a/html5ever/examples/print-tree-actions.rs +++ b/html5ever/examples/print-tree-actions.rs @@ -155,10 +155,16 @@ impl TreeSink for Sink { println!("Set current line to {}", line_number); } + #[cfg(api_v2)] fn pop(&mut self, elem: &usize) -> Result<(), SuperfluousClosingElement> { println!("Popped element {}", elem); Ok(()) } + + #[cfg(not(api_v2))] + fn pop(&mut self, elem: &usize) { + println!("Popped element {}", elem); + } } fn main() { From dca1bb552fbbe6a2f5c2c9c7c02ec11d46e6d0a9 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 16:35:34 +0300 Subject: [PATCH 11/25] corrected Cargo.toml files --- html5ever/Cargo.toml | 4 ++++ rcdom/Cargo.toml | 4 ++++ xml5ever/Cargo.toml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/html5ever/Cargo.toml b/html5ever/Cargo.toml index 3caf8c61..cf4014d8 100644 --- a/html5ever/Cargo.toml +++ b/html5ever/Cargo.toml @@ -28,3 +28,7 @@ proc-macro2 = "1" [[bench]] name = "html5ever" harness = false + +[features] +# Always use this feature in new code. In the future it will become the default. +api_v2 = [] diff --git a/rcdom/Cargo.toml b/rcdom/Cargo.toml index 5a5c0aed..193c6d23 100644 --- a/rcdom/Cargo.toml +++ b/rcdom/Cargo.toml @@ -39,3 +39,7 @@ harness = false [[test]] name = "xml-tokenizer" harness = false + +[features] +# Always use this feature in new code. In the future it will become the default. +api_v2 = [] diff --git a/xml5ever/Cargo.toml b/xml5ever/Cargo.toml index f20ea013..f77b21a3 100644 --- a/xml5ever/Cargo.toml +++ b/xml5ever/Cargo.toml @@ -28,3 +28,7 @@ criterion = "0.3" [[bench]] name = "xml5ever" harness = false + +[features] +# Always use this feature in new code. In the future it will become the default. +api_v2 = [] From b4edb3e9de6c204dfe257628fc8e611b3371919a Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 17:25:33 +0300 Subject: [PATCH 12/25] bug fix --- html5ever/src/tree_builder/mod.rs | 94 ++++++++++++++++++++--------- html5ever/src/tree_builder/rules.rs | 9 +-- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 5a4190d2..70f12adf 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -400,29 +400,31 @@ where use self::tag_sets::*; declare_tag_set!(foster_target = "table" "tbody" "tfoot" "thead" "tr"); - let target = override_target.unwrap_or_else(|| self.current_node().clone()); - if !(self.foster_parenting && self.elem_in(&target, foster_target)) { - if self.html_elem_named(&target, local_name!("template")) { - // No foster parenting (inside template). - let contents = self.sink.get_template_contents(&target); - return LastChild(contents); - } else { - // No foster parenting (the common case). - return LastChild(target); + if let Some(current_node) = self.current_node_v2() { + let target = override_target.unwrap_or_else(|| current_node.clone()); + if !(self.foster_parenting && self.elem_in(&target, foster_target)) { + if self.html_elem_named(&target, local_name!("template")) { + // No foster parenting (inside template). + let contents = self.sink.get_template_contents(&target); + return LastChild(contents); + } else { + // No foster parenting (the common case). + return LastChild(target); + } } - } - // Foster parenting - let mut iter = self.open_elems.iter().rev().peekable(); - while let Some(elem) = iter.next() { - if self.html_elem_named(&elem, local_name!("template")) { - let contents = self.sink.get_template_contents(&elem); - return LastChild(contents); - } else if self.html_elem_named(&elem, local_name!("table")) { - return TableFosterParenting { - element: elem.clone(), - prev_element: (*iter.peek().unwrap()).clone(), - }; + // Foster parenting + let mut iter = self.open_elems.iter().rev().peekable(); + while let Some(elem) = iter.next() { + if self.html_elem_named(&elem, local_name!("template")) { + let contents = self.sink.get_template_contents(&elem); + return LastChild(contents); + } else if self.html_elem_named(&elem, local_name!("table")) { + return TableFosterParenting { + element: elem.clone(), + prev_element: (*iter.peek().unwrap()).clone(), + }; + } } } let html_elem = self.html_elem(); @@ -532,8 +534,15 @@ where } fn adjusted_current_node_present_but_not_in_html_namespace(&self) -> bool { - !self.open_elems.is_empty() && - self.sink.elem_name(self.adjusted_current_node()).ns != &ns!(html) + if !self.open_elems.is_empty() { + if let Some(current) = self.adjusted_current_node_v2() { + self.sink.elem_name(current).ns != &ns!(html) + } else { + false + } + } else { + false + } } } @@ -661,11 +670,12 @@ where #[cfg(api_v2)] /// Like current_node(), but in the case of no open element, just warn instead of returning an error. fn current_node_unconditional(&self) -> &Handle { - let current = self.current_node(); - if self.current_node_v2().is_none() { + if let Some(current) = self.current_node_v2() { + current + } else { warn!("no current element"); + self.html_elem() } - current } #[cfg(not(api_v2))] @@ -679,6 +689,7 @@ where self.open_elems.last() } + // FIXME: Deprecate fn adjusted_current_node(&self) -> &Handle { if self.open_elems.len() == 1 { if let Some(ctx) = self.context_elem.as_ref() { @@ -688,6 +699,17 @@ where self.current_node() } + // FIXME: Deprecate + // #[cfg(api_v2)] + fn adjusted_current_node_v2(&self) -> Option<&Handle> { + if self.open_elems.len() == 1 { + if let Some(ctx) = self.context_elem.as_ref() { + return Some(ctx); + } + } + self.current_node_v2() + } + fn current_node_in(&self, set: TagSet) -> bool where TagSet: Fn(ExpandedName) -> bool, @@ -1073,7 +1095,11 @@ where } fn current_node_named(&self, name: LocalName) -> bool { - self.html_elem_named(self.current_node(), name) + if let Some(current) = self.current_node_v2() { + self.html_elem_named(current, name) + } else { + false + } } fn in_scope_named(&self, scope: TagSet, name: LocalName) -> bool @@ -1472,6 +1498,10 @@ where return false; } + if self.adjusted_current_node_v2().is_none() { // hack + return false; + } + let name = self.sink.elem_name(self.adjusted_current_node()); if let ns!(html) = *name.ns { return false; @@ -1507,9 +1537,13 @@ where .. }) => return false, CharacterTokens(..) | NullCharacterToken | TagToken(Tag { kind: StartTag, .. }) => { - return !self - .sink - .is_mathml_annotation_xml_integration_point(self.adjusted_current_node()); + if let Some(current) = self.adjusted_current_node_v2() { + return !self + .sink + .is_mathml_annotation_xml_integration_point(current); + } else { + return false; + } }, _ => {}, }; diff --git a/html5ever/src/tree_builder/rules.rs b/html5ever/src/tree_builder/rules.rs index c7f0c4ca..0ed242c4 100644 --- a/html5ever/src/tree_builder/rules.rs +++ b/html5ever/src/tree_builder/rules.rs @@ -469,10 +469,11 @@ where return Done; } self.generate_implied_end(cursory_implied_end); - let current = self.current_node().clone(); - self.remove_from_stack(&node); - if !self.sink.same_node(¤t, &node) { - self.sink.parse_error(Borrowed("Bad open element on ")); + if let Some(current) = self.current_node_v2() { + self.remove_from_stack(&node); + if !self.sink.same_node(&self.current_node().clone(), &node) { + self.sink.parse_error(Borrowed("Bad open element on ")); + } } } else { if !self.in_scope_named(default_scope, local_name!("form")) { From 5b056dec2b66e03fbb2270e471b5956fcb51475e Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 17:53:10 +0300 Subject: [PATCH 13/25] bug fix --- html5ever/src/tree_builder/mod.rs | 3 ++- markup5ever/interface/tree_builder.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 70f12adf..e9b7dd63 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -660,9 +660,10 @@ where self.current_node_v2() } + // FIXME: #[cfg] seems not to work together with deprecated. /// Indicate that a node was popped off the stack of open elements. + // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] #[cfg(not(api_v2))] - #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn current_node(&self) -> &Handle { self.open_elems.last().expect("no current element") } diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index ea02e0ed..e20846c1 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -211,9 +211,10 @@ pub trait TreeSink { self.pop_v2(node) } + // FIXME: #[cfg] seems not to work together with deprecated. /// Indicate that a node was popped off the stack of open elements. #[cfg(not(api_v2))] - #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn pop(&mut self, _node: &Self::Handle) {} #[cfg(api_v2)] From a8a98aeff83ca1f2e6bbdecdab897dd9457d20ae Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:06:52 +0300 Subject: [PATCH 14/25] bug fix --- html5ever/examples/print-tree-actions.rs | 4 ++-- html5ever/src/tree_builder/mod.rs | 13 ++++++------- markup5ever/interface/tree_builder.rs | 11 +++++------ xml5ever/src/tree_builder/mod.rs | 14 +++++++------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/html5ever/examples/print-tree-actions.rs b/html5ever/examples/print-tree-actions.rs index bd280669..b493eb21 100644 --- a/html5ever/examples/print-tree-actions.rs +++ b/html5ever/examples/print-tree-actions.rs @@ -155,13 +155,13 @@ impl TreeSink for Sink { println!("Set current line to {}", line_number); } - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] fn pop(&mut self, elem: &usize) -> Result<(), SuperfluousClosingElement> { println!("Popped element {}", elem); Ok(()) } - #[cfg(not(api_v2))] + #[cfg(not(feature = "api_v2"))] fn pop(&mut self, elem: &usize) { println!("Popped element {}", elem); } diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index e9b7dd63..b1f6493b 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -655,20 +655,19 @@ where //§ END /// Indicate that a node was popped off the stack of open elements. - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] fn current_node(&self) -> Option<&Handle> { self.current_node_v2() } - // FIXME: #[cfg] seems not to work together with deprecated. /// Indicate that a node was popped off the stack of open elements. - // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] - #[cfg(not(api_v2))] + #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + #[cfg(not(feature = "api_v2"))] fn current_node(&self) -> &Handle { self.open_elems.last().expect("no current element") } - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] /// Like current_node(), but in the case of no open element, just warn instead of returning an error. fn current_node_unconditional(&self) -> &Handle { if let Some(current) = self.current_node_v2() { @@ -679,7 +678,7 @@ where } } - #[cfg(not(api_v2))] + #[cfg(not(feature = "api_v2"))] /// Like current_node(), but in the case of no open element, just warn instead of returning an error. fn current_node_unconditional(&self) -> &Handle { self.current_node() @@ -701,7 +700,7 @@ where } // FIXME: Deprecate - // #[cfg(api_v2)] + // #[cfg(feature = "api_v2")] fn adjusted_current_node_v2(&self) -> Option<&Handle> { if self.open_elems.len() == 1 { if let Some(ctx) = self.context_elem.as_ref() { diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index e20846c1..86ffc9fc 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -206,18 +206,17 @@ pub trait TreeSink { fn mark_script_already_started(&mut self, _node: &Self::Handle) {} /// Indicate that a node was popped off the stack of open elements. - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] fn pop(&mut self, _node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { self.pop_v2(node) } - // FIXME: #[cfg] seems not to work together with deprecated. /// Indicate that a node was popped off the stack of open elements. - #[cfg(not(api_v2))] - // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] + #[cfg(not(feature = "api_v2"))] + #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] fn pop(&mut self, _node: &Self::Handle) {} - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] /// Like pop(), but in the case of no open element, just warn instead of returning an error. fn pop_unconditional(&mut self, node: &Self::Handle) { if self.pop_v2(node).is_err() { @@ -225,7 +224,7 @@ pub trait TreeSink { }; } - #[cfg(not(api_v2))] + #[cfg(not(feature = "api_v2"))] /// Like pop(), but in the case of no open element, just warn instead of returning an error. fn pop_unconditional(&mut self, node: &Self::Handle) { #[allow(deprecated)] diff --git a/xml5ever/src/tree_builder/mod.rs b/xml5ever/src/tree_builder/mod.rs index b0814bce..aa94f248 100644 --- a/xml5ever/src/tree_builder/mod.rs +++ b/xml5ever/src/tree_builder/mod.rs @@ -438,13 +438,13 @@ where } /// Indicate that a node was popped off the stack of open elements. -// #[cfg(api_v2)] +// #[cfg(feature = "api_v2")] // fn current_node(open_elems: &[Handle]) -> Option<&Handle> { // current_node_v2(open_elems) // } // /// Indicate that a node was popped off the stack of open elements. -// #[cfg(not(api_v2))] +// #[cfg(not(feature = "api_v2"))] // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] // fn current_node(open_elems: &[Handle]) -> &Handle { // current_node_unconditional(open_elems) @@ -609,12 +609,12 @@ where self.open_elems.is_empty() } - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] fn pop(&mut self) -> Result { self.pop_v2() } - #[cfg(not(api_v2))] + #[cfg(not(feature = "api_v2"))] fn pop(&mut self) -> Handle { if let Ok(result) = self.pop_v2() { result @@ -623,21 +623,21 @@ where } } - // #[cfg(not(api_v2))] + // #[cfg(not(feature = "api_v2"))] // #[deprecated(note = "You are using an outdated API. Please use api_v2 feature.")] // fn pop(&mut self) -> Handle { // self.pop_unconditional() // } /// Like pop(), but in the case of no open element, just warn instead of returning an error. - #[cfg(api_v2)] + #[cfg(feature = "api_v2")] fn pop_unconditional(&mut self) { if self.pop_v2().is_err() { warn!("no current element"); } } - #[cfg(not(api_v2))] + #[cfg(not(feature = "api_v2"))] fn pop_unconditional(&mut self) -> Handle { self.pop() } From 3fca2654162f8baa811cbb6a3d8e36c3a86be96f Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:08:20 +0300 Subject: [PATCH 15/25] bug fix --- markup5ever/interface/tree_builder.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index 86ffc9fc..c9a68bca 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -11,6 +11,9 @@ //! //! It can be used by a parser to create the DOM graph structure in memory. +#[cfg(feature = "api_v2")] +use log::warn; + use crate::interface::{Attribute, ExpandedName, QualName}; use std::borrow::Cow; use tendril::StrTendril; @@ -207,7 +210,7 @@ pub trait TreeSink { /// Indicate that a node was popped off the stack of open elements. #[cfg(feature = "api_v2")] - fn pop(&mut self, _node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { + fn pop(&mut self, node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { self.pop_v2(node) } From 42cffa6975851c9e8b3369e1a91c616b47a09f14 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:11:17 +0300 Subject: [PATCH 16/25] bug fix --- html5ever/src/tree_builder/mod.rs | 2 +- html5ever/src/tree_builder/rules.rs | 2 +- xml5ever/src/tree_builder/mod.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index b1f6493b..33ad4574 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -696,7 +696,7 @@ where return ctx; } } - self.current_node() + self.current_node_unconditional() } // FIXME: Deprecate diff --git a/html5ever/src/tree_builder/rules.rs b/html5ever/src/tree_builder/rules.rs index 0ed242c4..10fc3cc5 100644 --- a/html5ever/src/tree_builder/rules.rs +++ b/html5ever/src/tree_builder/rules.rs @@ -471,7 +471,7 @@ where self.generate_implied_end(cursory_implied_end); if let Some(current) = self.current_node_v2() { self.remove_from_stack(&node); - if !self.sink.same_node(&self.current_node().clone(), &node) { + if !self.sink.same_node(&self.current_node_unconditional().clone(), &node) { self.sink.parse_error(Borrowed("Bad open element on ")); } } diff --git a/xml5ever/src/tree_builder/mod.rs b/xml5ever/src/tree_builder/mod.rs index aa94f248..825fbb84 100644 --- a/xml5ever/src/tree_builder/mod.rs +++ b/xml5ever/src/tree_builder/mod.rs @@ -609,10 +609,10 @@ where self.open_elems.is_empty() } - #[cfg(feature = "api_v2")] - fn pop(&mut self) -> Result { - self.pop_v2() - } + // #[cfg(feature = "api_v2")] + // fn pop(&mut self) -> Result { + // self.pop_v2() + // } #[cfg(not(feature = "api_v2"))] fn pop(&mut self) -> Handle { From 217eb49627bdc5acfbdacfa9019df62caf305279 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:20:47 +0300 Subject: [PATCH 17/25] bug fix --- html5ever/src/tree_builder/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 33ad4574..f882eb28 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -178,6 +178,15 @@ where } } + // TODO: Hack to prevent accessing empty stack. + fn pop_open_elem(&mut self) -> Option { + if !self.open_elems.is_empty() { + self.open_elems.pop() + } else { + None + } + } + /// Create a new tree builder which sends tree modifications to a particular `TreeSink`. /// This is for parsing fragments. /// From 50935ef8f53e3b71f350298c8ac5c289f4bbdbe3 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:22:54 +0300 Subject: [PATCH 18/25] bug fix --- html5ever/src/tree_builder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index f882eb28..bf44de08 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -180,7 +180,7 @@ where // TODO: Hack to prevent accessing empty stack. fn pop_open_elem(&mut self) -> Option { - if !self.open_elems.is_empty() { + if self.open_elems.len() > 1 { self.open_elems.pop() } else { None From 3458f4cb23f3d461a25b58533ddb76ba88079380 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:25:03 +0300 Subject: [PATCH 19/25] bug fix --- html5ever/src/tree_builder/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index bf44de08..480eeab9 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -181,7 +181,7 @@ where // TODO: Hack to prevent accessing empty stack. fn pop_open_elem(&mut self) -> Option { if self.open_elems.len() > 1 { - self.open_elems.pop() + self.pop_open_elem() } else { None } @@ -1155,7 +1155,7 @@ where if self.current_node_in(|x| pred(x)) { break; } - self.open_elems.pop(); + self.pop_open_elem(); } } @@ -1168,7 +1168,7 @@ where let mut n = 0; loop { n += 1; - match self.open_elems.pop() { + match self.pop_open_elem() { None => break, Some(elem) => { if pred(self.sink.elem_name(&elem)) { From 3a017f408cfd946cb783a7f1f07324c3583ca66b Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:28:53 +0300 Subject: [PATCH 20/25] bug fix --- html5ever/src/tree_builder/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 480eeab9..6f36a771 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -181,7 +181,7 @@ where // TODO: Hack to prevent accessing empty stack. fn pop_open_elem(&mut self) -> Option { if self.open_elems.len() > 1 { - self.pop_open_elem() + self.open_elems.pop() } else { None } @@ -943,7 +943,7 @@ where } fn pop_v2(&mut self) -> Result { - if let Some(elem) = self.open_elems.pop() { + if let Some(elem) = self.pop_open_elem() { self.sink.pop(&elem); Ok(elem) } else { From 11b3fe7d95a066cc67763a29dec299169b5a7a02 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 18:51:24 +0300 Subject: [PATCH 21/25] tests bug fix --- html5ever/examples/print-tree-actions.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/html5ever/examples/print-tree-actions.rs b/html5ever/examples/print-tree-actions.rs index b493eb21..74e1437f 100644 --- a/html5ever/examples/print-tree-actions.rs +++ b/html5ever/examples/print-tree-actions.rs @@ -17,12 +17,14 @@ use std::io; use html5ever::parse_document; use html5ever::tendril::*; -use html5ever::tree_builder::TreeBuilder; use html5ever::tree_builder::{ AppendNode, AppendText, ElementFlags, NodeOrText, QuirksMode, TreeSink, }; use html5ever::{Attribute, ExpandedName, QualName}; +#[cfg(feature = "api_v2")] +use markup5ever::interface::tree_builder::SuperfluousClosingElement; + struct Sink { next_id: usize, names: HashMap, From 6f37a21e269696dad641009c3867d55f3ab3b15a Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 19:32:06 +0300 Subject: [PATCH 22/25] bug fix --- markup5ever/interface/tree_builder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index c9a68bca..c39f140c 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -237,6 +237,7 @@ pub trait TreeSink { /// Indicate that a node was popped off the stack of open elements. /// /// Note: Don't use this function, use pop() with api_v2 feature instead. + #[cfg(feature = "api_v2")] fn pop_v2(&mut self, _node: &Self::Handle) -> Result<(), SuperfluousClosingElement> { Ok(()) } From f8fb3ac45a0e9c17771982a2c1fff25047115ec1 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Sun, 25 Jul 2021 20:56:25 +0300 Subject: [PATCH 23/25] fixes --- html5ever/src/tree_builder/mod.rs | 35 +++++++++++++++++---------- markup5ever/interface/tree_builder.rs | 4 +++ xml5ever/src/tree_builder/mod.rs | 11 ++------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/html5ever/src/tree_builder/mod.rs b/html5ever/src/tree_builder/mod.rs index 6f36a771..a14a591b 100644 --- a/html5ever/src/tree_builder/mod.rs +++ b/html5ever/src/tree_builder/mod.rs @@ -687,29 +687,34 @@ where } } + #[cfg(feature = "api_v2")] + /// Like current_node(), but in the case of no open element, just warn instead of returning an error. + fn current_node(&self) -> &Handle { + self.current_node_unconditional() + } + #[cfg(not(feature = "api_v2"))] /// Like current_node(), but in the case of no open element, just warn instead of returning an error. fn current_node_unconditional(&self) -> &Handle { self.current_node() } - /// Note: Don't use this function, use pop() with api_v2 feature instead. + #[doc(hidden)] fn current_node_v2(&self) -> Option<&Handle> { self.open_elems.last() } - // FIXME: Deprecate - fn adjusted_current_node(&self) -> &Handle { - if self.open_elems.len() == 1 { - if let Some(ctx) = self.context_elem.as_ref() { - return ctx; - } - } - self.current_node_unconditional() + #[cfg(feature = "api_v2")] + fn adjusted_current_node(&self) -> Option<&Handle> { + self.adjusted_current_node_v2() + } + + #[cfg(not(feature = "api_v2"))] + fn adjusted_current_node(&self) { + self.adjusted_current_node() } - // FIXME: Deprecate - // #[cfg(feature = "api_v2")] + #[doc(hidden)] fn adjusted_current_node_v2(&self) -> Option<&Handle> { if self.open_elems.len() == 1 { if let Some(ctx) = self.context_elem.as_ref() { @@ -719,6 +724,10 @@ where self.current_node_v2() } + fn adjusted_current_node_unconditional(&self) -> &Handle { + self.adjusted_current_node_v2().expect("no current node") + } + fn current_node_in(&self, set: TagSet) -> bool where TagSet: Fn(ExpandedName) -> bool, @@ -1511,7 +1520,7 @@ where return false; } - let name = self.sink.elem_name(self.adjusted_current_node()); + let name = self.sink.elem_name(self.adjusted_current_node_unconditional()); if let ns!(html) = *name.ns { return false; } @@ -1724,7 +1733,7 @@ where } fn foreign_start_tag(&mut self, mut tag: Tag) -> ProcessResult { - let current_ns = self.sink.elem_name(self.adjusted_current_node()).ns.clone(); + let current_ns = self.sink.elem_name(self.adjusted_current_node_unconditional()).ns.clone(); match current_ns { ns!(mathml) => self.adjust_mathml_attributes(&mut tag), ns!(svg) => { diff --git a/markup5ever/interface/tree_builder.rs b/markup5ever/interface/tree_builder.rs index c39f140c..575e851d 100644 --- a/markup5ever/interface/tree_builder.rs +++ b/markup5ever/interface/tree_builder.rs @@ -208,6 +208,10 @@ pub trait TreeSink { /// Mark a HTML `