diff options
| -rw-r--r-- | src/default_emitter.rs | 239 | ||||
| -rw-r--r-- | src/let_else.rs | 23 | ||||
| -rw-r--r-- | src/lib.rs | 1 | 
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; @@ -11,6 +11,7 @@ mod default_emitter;  mod emitter;  mod entities;  mod error; +mod let_else;  mod naive_parser;  mod tokenizer; | 
