aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/default_emitter.rs239
-rw-r--r--src/let_else.rs23
-rw-r--r--src/lib.rs1
3 files changed, 114 insertions, 149 deletions
diff --git a/src/default_emitter.rs b/src/default_emitter.rs
index e975392..1559021 100644
--- a/src/default_emitter.rs
+++ b/src/default_emitter.rs
@@ -3,6 +3,7 @@ use std::collections::BTreeSet;
use std::collections::VecDeque;
use std::ops::Range;
+use crate::let_else::assume;
use crate::offset::NoopOffset;
use crate::offset::Offset;
use crate::token::{AttrValueSyntax, Comment, Doctype, EndTag, StartTag, Token};
@@ -80,31 +81,22 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
}
fn push_tag_name(&mut self, s: &str) {
- match self.current_token {
- Some(Token::StartTag(StartTag { ref mut name, .. })) => {
- name.push_str(s);
- }
- Some(Token::EndTag(EndTag { ref mut name, .. })) => {
- name.push_str(s);
- }
- _ => debug_assert!(false),
- }
+ assume!(
+ Some(Token::StartTag(StartTag { name, .. }) | Token::EndTag(EndTag { name, .. })),
+ &mut self.current_token
+ );
+ name.push_str(s);
}
fn terminate_tag_name(&mut self, offset: O) {
- match self.current_token {
- Some(Token::StartTag(StartTag {
- ref mut name_span, ..
- })) => {
- name_span.end = offset;
- }
- Some(Token::EndTag(EndTag {
- ref mut name_span, ..
- })) => {
- name_span.end = offset;
- }
- _ => debug_assert!(false),
- }
+ assume!(
+ Some(
+ Token::StartTag(StartTag { name_span, .. })
+ | Token::EndTag(EndTag { name_span, .. })
+ ),
+ &mut self.current_token
+ );
+ name_span.end = offset;
}
fn init_attribute_name(&mut self, offset: O) {
@@ -147,20 +139,16 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
}
fn set_self_closing(&mut self, slash_span: Range<O>) {
- let tag = self.current_token.as_mut().unwrap();
- match tag {
- Token::StartTag(StartTag {
- ref mut self_closing,
- ..
- }) => {
- *self_closing = true;
+ let token = self.current_token.as_mut().unwrap();
+
+ match token {
+ Token::StartTag(tag) => {
+ tag.self_closing = true;
}
Token::EndTag(_) => {
self.report_error(Error::EndTagWithTrailingSolidus, slash_span);
}
- _ => {
- debug_assert!(false);
- }
+ other => debug_assert!(false, "unexpected current_token: {other:?}"),
}
}
@@ -179,7 +167,10 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
Token::StartTag(tag) => {
tag.span.end = offset;
}
- _ => debug_assert!(false),
+ other => {
+ debug_assert!(false, "unexpected current_token: {other:?}");
+ return;
+ }
}
self.emit_token(token);
}
@@ -192,19 +183,14 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
}
fn push_comment(&mut self, s: &str) {
- match self.current_token {
- Some(Token::Comment(Comment { ref mut data, .. })) => data.push_str(s),
- _ => debug_assert!(false),
- }
+ assume!(Some(Token::Comment(comment)), &mut self.current_token);
+ comment.data.push_str(s);
}
fn emit_current_comment(&mut self, data_end_offset: O) {
let mut token = self.current_token.take().unwrap();
- if let Token::Comment(comment) = &mut token {
- comment.data_span.end = data_end_offset;
- } else {
- debug_assert!(false);
- }
+ assume!(Token::Comment(comment), &mut token);
+ comment.data_span.end = data_end_offset;
self.emit_token(token);
}
@@ -222,110 +208,78 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
}
fn init_doctype_name(&mut self, offset: O) {
- let Some(Token::Doctype(doctype)) = &mut self.current_token else {
- debug_assert!(false);
- return;
- };
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
doctype.name = Some("".into());
doctype.name_span.start = offset;
}
fn push_doctype_name(&mut self, s: &str) {
- match self.current_token {
+ assume!(
Some(Token::Doctype(Doctype {
- name: Some(ref mut name),
+ name: Some(name),
..
- })) => name.push_str(s),
- _ => debug_assert!(false),
- }
+ })),
+ &mut self.current_token
+ );
+ name.push_str(s);
}
fn terminate_doctype_name(&mut self, offset: O) {
- let Some(Token::Doctype(doctype)) = &mut self.current_token else {
- debug_assert!(false);
- return;
- };
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
doctype.name_span.end = offset;
}
fn init_doctype_public_id(&mut self, offset: O) {
- let Some(Token::Doctype(doctype)) = &mut self.current_token else {
- debug_assert!(false);
- return;
- };
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
doctype.public_id = Some("".to_owned());
doctype.public_id_span.start = offset;
}
fn push_doctype_public_id(&mut self, s: &str) {
- if let Some(Token::Doctype(Doctype {
- public_id: Some(ref mut id),
- ..
- })) = self.current_token
- {
- id.push_str(s);
- } else {
- debug_assert!(false);
- }
+ assume!(
+ Some(Token::Doctype(Doctype {
+ public_id: Some(public_id),
+ ..
+ })),
+ &mut self.current_token
+ );
+ public_id.push_str(s);
}
fn terminate_doctype_public_id(&mut self, offset: O) {
- if let Some(Token::Doctype(Doctype {
- ref mut public_id_span,
- ..
- })) = self.current_token
- {
- public_id_span.end = offset;
- } else {
- debug_assert!(false);
- }
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
+ doctype.public_id_span.end = offset;
}
fn init_doctype_system_id(&mut self, offset: O) {
- let Some(Token::Doctype(doctype)) = &mut self.current_token else {
- debug_assert!(false);
- return;
- };
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
doctype.system_id = Some("".to_owned());
doctype.system_id_span.start = offset;
}
fn push_doctype_system_id(&mut self, s: &str) {
- if let Some(Token::Doctype(Doctype {
- system_id: Some(ref mut id),
- ..
- })) = self.current_token
- {
- id.push_str(s);
- } else {
- debug_assert!(false);
- }
+ assume!(
+ Some(Token::Doctype(Doctype {
+ system_id: Some(id),
+ ..
+ })),
+ &mut self.current_token
+ );
+ id.push_str(s);
}
fn terminate_doctype_system_id(&mut self, offset: O) {
- if let Some(Token::Doctype(Doctype {
- ref mut system_id_span,
- ..
- })) = self.current_token
- {
- system_id_span.end = offset;
- } else {
- debug_assert!(false);
- }
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
+ doctype.system_id_span.end = offset;
}
fn set_force_quirks(&mut self) {
- match self.current_token {
- Some(Token::Doctype(ref mut doctype)) => doctype.force_quirks = true,
- _ => debug_assert!(false),
- }
+ assume!(Some(Token::Doctype(doctype)), &mut self.current_token);
+ doctype.force_quirks = true;
}
fn emit_current_doctype(&mut self, offset: O) {
- let Some(Token::Doctype(mut doctype)) = self.current_token.take() else {
- debug_assert!(false);
- return;
- };
+ assume!(Some(Token::Doctype(mut doctype)), self.current_token.take());
doctype.span.end = offset;
self.emit_token(Token::Doctype(doctype));
}
@@ -340,26 +294,25 @@ impl<O> DefaultEmitter<O> {
where
O: Offset,
{
- if let Some((name, map_val)) = self.current_attribute.take() {
- match self.current_token {
- Some(Token::StartTag(ref mut tag)) => match tag.attributes.inner.entry(name) {
- Entry::Vacant(vacant) => {
- vacant.insert(map_val);
- }
- Entry::Occupied(_) => {
- self.report_error(Error::DuplicateAttribute, map_val.name_span);
- }
- },
- Some(Token::EndTag(_)) => {
- self.attr_in_end_tag_span = Some(map_val.name_span.clone());
- if !self.seen_attributes.insert(name) {
- self.report_error(Error::DuplicateAttribute, map_val.name_span);
- }
+ let Some((name, attr_internal)) = self.current_attribute.take() else {
+ return;
+ };
+ match &mut self.current_token {
+ Some(Token::StartTag(tag)) => match tag.attributes.inner.entry(name) {
+ Entry::Vacant(vacant) => {
+ vacant.insert(attr_internal);
+ }
+ Entry::Occupied(_) => {
+ self.report_error(Error::DuplicateAttribute, attr_internal.name_span);
}
- _ => {
- debug_assert!(false);
+ },
+ Some(Token::EndTag(_)) => {
+ self.attr_in_end_tag_span = Some(attr_internal.name_span.clone());
+ if !self.seen_attributes.insert(name) {
+ self.report_error(Error::DuplicateAttribute, attr_internal.name_span);
}
}
+ other => debug_assert!(false, "unexpected current_token: {other:?}"),
}
}
}
@@ -380,32 +333,20 @@ mod tests {
DefaultEmitter::default(),
)
.flatten();
- let Event::Token(Token::StartTag(start_tag)) = tokenizer.next().unwrap() else {
+ let Event::Token(Token::StartTag(tag)) = tokenizer.next().unwrap() else {
panic!("expected start tag");
};
- assert_eq!(
- start_tag.attributes.get("empty").unwrap().value_syntax(),
- None
- );
- assert_eq!(
- start_tag.attributes.get("unquoted").unwrap().value_syntax(),
- Some(AttrValueSyntax::Unquoted)
- );
- assert_eq!(
- start_tag
- .attributes
- .get("single-quoted")
- .unwrap()
- .value_syntax(),
- Some(AttrValueSyntax::SingleQuoted)
- );
- assert_eq!(
- start_tag
- .attributes
- .get("double-quoted")
- .unwrap()
- .value_syntax(),
- Some(AttrValueSyntax::DoubleQuoted)
- );
+ for (name, syntax) in [
+ ("empty", None),
+ ("unquoted", Some(AttrValueSyntax::Unquoted)),
+ ("single-quoted", Some(AttrValueSyntax::SingleQuoted)),
+ ("double-quoted", Some(AttrValueSyntax::DoubleQuoted)),
+ ] {
+ assert_eq!(
+ tag.attributes.get(name).unwrap().value_syntax(),
+ syntax,
+ "unexpected value for attribute {name}"
+ );
+ }
}
}
diff --git a/src/let_else.rs b/src/let_else.rs
new file mode 100644
index 0000000..da17a68
--- /dev/null
+++ b/src/let_else.rs
@@ -0,0 +1,23 @@
+/// Binds the given expression to the given pattern, or else executes
+/// `debug_assert!(false);` with a helpful panic message and returns.
+macro_rules! assume {
+ ($pattern:pat, $value:expr) => {
+ // The expression might change each time it's evaluated, so we
+ // have to bind it so that we can reuse it in the panic message.
+ let _value = $value;
+
+ let $pattern = _value else {
+ debug_assert!(
+ false,
+ "assertion `left matches right` failed:
+ left: {}
+right: {:?}",
+ stringify!($pattern),
+ _value
+ );
+ return;
+ };
+ };
+}
+
+pub(crate) use assume;
diff --git a/src/lib.rs b/src/lib.rs
index 3c7e77b..40b691a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,7 @@ mod default_emitter;
mod emitter;
mod entities;
mod error;
+mod let_else;
mod naive_parser;
mod tokenizer;