chore: replace some debug_assert with explicit panic

This commit is contained in:
PoiScript 2024-05-09 11:02:46 +08:00
parent b9a3c7a889
commit 8a29a46095
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
16 changed files with 145 additions and 139 deletions

View file

@ -15,7 +15,7 @@ fn main() {
let content = fs::read_to_string(&args[1]).unwrap();
let mut export = MarkdownExport::default();
Org::parse(&content).traverse(&mut export);
Org::parse(content).traverse(&mut export);
fs::write(format!("{}.md", &args[1]), export.finish()).unwrap();

View file

@ -14,10 +14,7 @@ impl AffiliatedKeyword {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
.unwrap_or_else(|| {
debug_assert!(false, "keyword must contains TEXT");
Token::default()
})
.expect("keyword must contains TEXT")
}
///

View file

@ -74,10 +74,19 @@ impl SourceBlock {
/// ```rust
/// use orgize::{Org, ast::SourceBlock};
///
/// let block = Org::parse("#+begin_src\n#+end_src").first_node::<SourceBlock>().unwrap();
/// let block = Org::parse(r#"
/// #+begin_src
/// #+end_src
/// "#).first_node::<SourceBlock>().unwrap();
/// assert_eq!(block.value(), "");
/// let block = Org::parse("#+begin_src\n,* foo \n,#+ bar\n#+end_src").first_node::<SourceBlock>().unwrap();
/// assert_eq!(block.value(), "* foo \n#+ bar\n");
///
/// let block = Org::parse(r#"
/// #+begin_src
/// ,* foo
/// ,#+ bar
/// #+end_src
/// "#).first_node::<SourceBlock>().unwrap();
/// assert_eq!(block.value(), "* foo\n#+ bar\n");
/// ````
pub fn value(&self) -> String {
self.syntax
@ -116,17 +125,25 @@ macro_rules! impl_content_border {
/// Beginning position of block content
pub fn content_start(&self) -> TextSize {
self.syntax
.first_child()
.children()
.find(|n| n.kind() == SyntaxKind::BLOCK_BEGIN)
.map(|n| n.text_range().end())
.unwrap_or_else(|| self.syntax.text_range().start())
.unwrap_or_else(|| {
debug_assert!(false, "block must contains BLOCK_BEGIN");
TextSize::default()
})
}
/// Ending position of block content
pub fn content_end(&self) -> TextSize {
self.syntax
.last_child()
.children()
.find(|n| n.kind() == SyntaxKind::BLOCK_END)
.map(|n| n.text_range().start())
.unwrap_or_else(|| self.syntax.text_range().end())
.unwrap_or_else(|| {
debug_assert!(false, "block must contains BLOCK_END");
TextSize::default()
})
}
}
};

View file

@ -24,9 +24,9 @@ impl Clock {
.skip_while(|t| t.kind() != SyntaxKind::DOUBLE_ARROW)
.skip(1)
.find(|t| t.kind() != SyntaxKind::WHITESPACE)
.map(|e| {
debug_assert!(e.kind() == SyntaxKind::TEXT);
Token(e.into_token())
.and_then(|e| {
debug_assert_eq!(e.kind(), SyntaxKind::TEXT);
Some(Token(e.into_token()?))
})
}

View file

@ -65,17 +65,25 @@ impl PropertyDrawer {
/// Beginning position of drawer content
pub fn content_start(&self) -> TextSize {
self.syntax
.first_child()
.children()
.find(|n| n.kind() == SyntaxKind::DRAWER_BEGIN)
.map(|n| n.text_range().end())
.unwrap_or_else(|| self.syntax.text_range().start())
.unwrap_or_else(|| {
debug_assert!(false, "property drawer must contains DRAWER_BEGIN");
TextSize::default()
})
}
/// Ending position of drawer content
pub fn content_end(&self) -> TextSize {
self.syntax
.last_child()
.children()
.find(|n| n.kind() == SyntaxKind::DRAWER_END)
.map(|n| n.text_range().start())
.unwrap_or_else(|| self.syntax.text_range().end())
.unwrap_or_else(|| {
debug_assert!(false, "property drawer must contains DRAWER_END");
TextSize::default()
})
}
}
@ -89,30 +97,36 @@ impl Drawer {
/// ```
pub fn name(&self) -> Token {
self.syntax
.first_child()
.and_then(|n| {
n.children_with_tokens()
.filter_map(|e| e.into_token())
.find(|e| e.kind() == SyntaxKind::TEXT)
})
.map(|t| Token(Some(t)))
.unwrap_or_default()
.children()
.find(|n| n.kind() == SyntaxKind::DRAWER_BEGIN)
.expect("drawer must contains DRAWER_BEGIN")
.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
.expect("drawer begin must contains TEXT")
}
/// Beginning position of drawer content
pub fn content_start(&self) -> TextSize {
self.syntax
.first_child()
.children()
.find(|n| n.kind() == SyntaxKind::DRAWER_BEGIN)
.map(|n| n.text_range().end())
.unwrap_or_else(|| self.syntax.text_range().start())
.unwrap_or_else(|| {
debug_assert!(false, "drawer must contains DRAWER_BEGIN");
TextSize::default()
})
}
/// Ending position of drawer content
pub fn content_end(&self) -> TextSize {
self.syntax
.last_child()
.children()
.find(|n| n.kind() == SyntaxKind::DRAWER_END)
.map(|n| n.text_range().start())
.unwrap_or_else(|| self.syntax.text_range().end())
.unwrap_or_else(|| {
debug_assert!(false, "drawer must contains DRAWER_END");
TextSize::default()
})
}
/// Raw text of drawer content

View file

@ -27,7 +27,7 @@ impl Headline {
.find_map(filter_token(SyntaxKind::HEADLINE_STARS))
.map_or_else(
|| {
debug_assert!(false, "headline must contains starts token");
debug_assert!(false, "headline must contains HEADLINE_STARS");
0
},
|stars| stars.len(),
@ -48,7 +48,7 @@ impl Headline {
if tk.kind() == SyntaxKind::HEADLINE_KEYWORD_TODO
|| tk.kind() == SyntaxKind::HEADLINE_KEYWORD_DONE =>
{
Some(Token(Some(tk)))
Some(Token(tk))
}
_ => None,
})

View file

@ -15,10 +15,7 @@ impl InlineCall {
.children_with_tokens()
.filter_map(filter_token(SyntaxKind::TEXT))
.nth(1)
.unwrap_or_else(|| {
debug_assert!(false, "inline call must contains two TEXT");
Token::default()
})
.expect("inline call must contains two TEXT")
}
///
@ -27,15 +24,19 @@ impl InlineCall {
///
/// let call = Org::parse("call_square[:results output](4)").first_node::<InlineCall>().unwrap();
/// assert_eq!(call.inside_header().unwrap(), ":results output");
///
/// let call = Org::parse("call_square(4)[:results html]").first_node::<InlineCall>().unwrap();
/// assert!(call.inside_header().is_none());
/// ```
pub fn inside_header(&self) -> Option<Token> {
self.syntax
.children_with_tokens()
.take_while(|e| e.kind() != SyntaxKind::L_PARENS)
.skip_while(|e| e.kind() != SyntaxKind::L_BRACKET)
.nth(1)
.map(|e| {
debug_assert!(e.kind() == SyntaxKind::TEXT);
Token(e.into_token())
.and_then(|e| {
debug_assert_eq!(e.kind(), SyntaxKind::TEXT);
Some(Token(e.into_token()?))
})
}
@ -50,17 +51,8 @@ impl InlineCall {
self.syntax
.children_with_tokens()
.skip_while(|e| e.kind() != SyntaxKind::L_PARENS)
.nth(1)
.map_or_else(
|| {
debug_assert!(false);
Token::default()
},
|e| {
debug_assert!(e.kind() == SyntaxKind::TEXT);
Token(e.into_token())
},
)
.find_map(filter_token(SyntaxKind::TEXT))
.expect("inline call must contains TEXT after L_PARENS")
}
///
@ -69,6 +61,9 @@ impl InlineCall {
///
/// let call = Org::parse("call_square[:results output](4)[:results html]").first_node::<InlineCall>().unwrap();
/// assert_eq!(call.end_header().unwrap(), ":results html");
///
/// let call = Org::parse("call_square[:results output](4)").first_node::<InlineCall>().unwrap();
/// assert!(call.end_header().is_none());
/// ```
pub fn end_header(&self) -> Option<Token> {
self.syntax
@ -77,9 +72,9 @@ impl InlineCall {
.skip(1)
.skip_while(|e| e.kind() != SyntaxKind::L_BRACKET)
.nth(1)
.map(|e| {
debug_assert!(e.kind() == SyntaxKind::TEXT);
Token(e.into_token())
.and_then(|e| {
debug_assert_eq!(e.kind(), SyntaxKind::TEXT);
Some(Token(e.into_token()?))
})
}
}

View file

@ -18,10 +18,7 @@ impl InlineSrc {
.children_with_tokens()
.nth(1)
.and_then(filter_token(SyntaxKind::TEXT))
.unwrap_or_else(|| {
debug_assert!(false, "inline src must contains TEXT");
Token::default()
})
.expect("inline src must contains TEXT")
}
/// Optional header arguments
@ -39,9 +36,9 @@ impl InlineSrc {
.children_with_tokens()
.skip_while(|n| n.kind() != SyntaxKind::L_BRACKET)
.nth(1)
.map(|n| {
debug_assert!(n.kind() == SyntaxKind::TEXT);
Token(n.into_token())
.and_then(|n| {
debug_assert_eq!(n.kind(), SyntaxKind::TEXT);
Some(Token(n.into_token()?))
})
}
@ -60,9 +57,6 @@ impl InlineSrc {
.children_with_tokens()
.filter_map(filter_token(SyntaxKind::TEXT))
.last()
.unwrap_or_else(|| {
debug_assert!(false, "inline src must contains TEXT");
Token::default()
})
.expect("inline src must contains TEXT")
}
}

View file

@ -14,10 +14,7 @@ impl Keyword {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
.unwrap_or_else(|| {
debug_assert!(false, "keyword must contains TEXT");
Token::default()
})
.expect("keyword must contains TEXT")
}
///
@ -34,6 +31,6 @@ impl Keyword {
.children_with_tokens()
.filter_map(filter_token(SyntaxKind::TEXT))
.nth(1)
.unwrap_or_default()
.expect("keyword must contains two TEXT")
}
}

View file

@ -1,6 +1,6 @@
use rowan::ast::{support, AstNode};
use rowan::ast::AstNode;
use super::{AffiliatedKeyword, Link, Paragraph, Token};
use super::{token, AffiliatedKeyword, Link, Paragraph, Token};
use crate::{syntax::SyntaxKind, SyntaxElement};
impl Link {
@ -17,13 +17,7 @@ impl Link {
/// assert_eq!(link.path(), "https://google.com");
/// ```
pub fn path(&self) -> Token {
support::token(&self.syntax, SyntaxKind::LINK_PATH).map_or_else(
|| {
debug_assert!(false, "link must contains LINK_PATH");
Token::default()
},
|e| Token(Some(e)),
)
token(&self.syntax, SyntaxKind::LINK_PATH).expect("link must contains LINK_PATH")
}
/// Returns `true` if link contains description

View file

@ -85,10 +85,7 @@ impl ListItem {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::LIST_ITEM_BULLET))
.unwrap_or_else(|| {
debug_assert!(false, "list item must contains LIST_ITEM_BULLET");
Token::default()
})
.expect("list item must contains LIST_ITEM_BULLET")
}
/// ```rust

View file

@ -15,10 +15,7 @@ impl Macros {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
.unwrap_or_else(|| {
debug_assert!(false, "macros must contains TEXT");
Token::default()
})
.expect("macros must contains TEXT")
}
/// ```rust

View file

@ -1,7 +1,5 @@
#[rustfmt::skip]
mod generated;
mod affiliated_keyword;
mod block;
mod clock;
@ -22,13 +20,6 @@ mod snippet;
mod table;
mod timestamp;
use std::{
borrow::{Borrow, Cow},
fmt::Debug,
hash::Hash,
ops::Deref,
};
pub use generated::*;
pub use headline::*;
pub use rowan::ast::support::*;
@ -38,7 +29,13 @@ use crate::{
syntax::{SyntaxKind, SyntaxNode},
SyntaxToken,
};
use rowan::{ast::AstNode, NodeOrToken, TextSize};
use rowan::{ast::AstNode, NodeOrToken, TextRange, TextSize};
use std::{
borrow::{Borrow, Cow},
fmt,
hash::Hash,
ops::Deref,
};
pub fn blank_lines(parent: &SyntaxNode) -> usize {
parent
@ -59,52 +56,55 @@ pub fn last_token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<Token> {
}
pub fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<Token> {
rowan::ast::support::token(parent, kind).map(|t| Token(Some(t)))
rowan::ast::support::token(parent, kind).map(Token)
}
pub fn filter_token(
kind: SyntaxKind,
) -> impl Fn(NodeOrToken<SyntaxNode, SyntaxToken>) -> Option<Token> {
move |elem| match elem {
NodeOrToken::Token(tk) if tk.kind() == kind => Some(Token(Some(tk))),
NodeOrToken::Token(tk) if tk.kind() == kind => Some(Token(tk)),
_ => None,
}
}
/// A simple wrapper of `Option<SyntaxToken>`
/// A simple wrapper of `SyntaxToken`
///
/// It acts like a `token.text()` when inner is `Some(token)`, and an empty string when `None`.
#[derive(Default, Eq, Clone)]
pub struct Token(pub(crate) Option<SyntaxToken>);
/// It implements the `AsRef<str>` and `Display` trait,
/// allowing to directly use some `str` methods.
///
/// Also it implements `Hash` and `Eq` traits, so can be
/// used as keys in `HashMap`. However, note that it only
/// compares the underlying text inside `SyntaxToken`,
/// meaning two `Token`s from different positions
/// might be considered equal.
#[derive(Eq, Clone)]
pub struct Token(pub(crate) SyntaxToken);
impl Token {
pub fn syntax(&self) -> Option<&SyntaxToken> {
self.0.as_ref()
pub fn syntax(&self) -> &SyntaxToken {
&self.0
}
}
impl Token {
/// Range of this token
pub fn text_range(&self) -> TextRange {
self.0.text_range()
}
/// Beginning position of this token
pub fn start(&self) -> TextSize {
match &self.0 {
Some(t) => t.text_range().start(),
None => TextSize::new(0),
}
self.0.text_range().start()
}
/// Ending position of this token
pub fn end(&self) -> TextSize {
match &self.0 {
Some(t) => t.text_range().end(),
None => TextSize::new(0),
}
self.0.text_range().end()
}
}
impl AsRef<str> for Token {
fn as_ref(&self) -> &str {
match &self.0 {
Some(t) => t.text(),
None => "",
}
self.0.text()
}
}
@ -114,12 +114,6 @@ impl Borrow<str> for Token {
}
}
impl Debug for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_ref().fmt(f)
}
}
impl<'a> PartialEq<&'a str> for Token {
fn eq(&self, other: &&'a str) -> bool {
self.as_ref() == *other
@ -164,3 +158,15 @@ impl Deref for Token {
self.as_ref()
}
}
impl fmt::Debug for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.text(), f)
}
}
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.0.text(), f)
}
}

View file

@ -13,10 +13,7 @@ impl Snippet {
self.syntax
.children_with_tokens()
.find_map(filter_token(SyntaxKind::TEXT))
.unwrap_or_else(|| {
debug_assert!(false, "snippet must contains TEXT");
Token::default()
})
.expect("snippet must contains TEXT")
}
/// ```rust
@ -32,9 +29,6 @@ impl Snippet {
.children_with_tokens()
.filter_map(filter_token(SyntaxKind::TEXT))
.nth(1)
.unwrap_or_else(|| {
debug_assert!(false, "snippet must contains two TEXT");
Token::default()
})
.expect("snippet must contains two TEXT")
}
}

View file

@ -132,11 +132,15 @@ impl Traverser for HtmlExport {
Event::Leave(Container::Code(_)) => self.output += "</code>",
Event::Enter(Container::SourceBlock(block)) => {
let _ = write!(
&mut self.output,
r#"<pre><code class="language-{}">"#,
HtmlEscape(&block.language().unwrap_or_default())
);
if let Some(language) = block.language() {
let _ = write!(
&mut self.output,
r#"<pre><code class="language-{}">"#,
HtmlEscape(&language)
);
} else {
self.output += r#"<pre><code>"#
}
}
Event::Leave(Container::SourceBlock(_)) => self.output += "</code></pre>",

View file

@ -210,7 +210,7 @@ pub trait Traverser {
}
SyntaxElement::Token(token) => {
if token.kind() == TEXT {
self.event(Event::Text(Token(Some(token))), ctx);
self.event(Event::Text(Token(token)), ctx);
take_control!();
}
}