From 2128e86b816dc2b53ae41410e839b180ffc0b4a2 Mon Sep 17 00:00:00 2001 From: PoiScript Date: Sat, 9 May 2020 16:42:49 +0800 Subject: [PATCH] refactor: cleanup parse functions --- src/elements/block.rs | 271 +++++++++++++++++------------------ src/elements/clock.rs | 17 +-- src/elements/comment.rs | 51 ++++--- src/elements/cookie.rs | 43 +++--- src/elements/drawer.rs | 21 +-- src/elements/dyn_block.rs | 14 +- src/elements/fixed_width.rs | 51 ++++--- src/elements/fn_def.rs | 76 +++++----- src/elements/fn_ref.rs | 30 ++-- src/elements/inline_call.rs | 23 ++- src/elements/inline_src.rs | 25 ++-- src/elements/keyword.rs | 173 +++++++++++----------- src/elements/link.rs | 17 +-- src/elements/list.rs | 25 ++-- src/elements/macros.rs | 30 ++-- src/elements/radio_target.rs | 30 ++-- src/elements/rule.rs | 55 +++---- src/elements/snippet.rs | 30 ++-- src/elements/table.rs | 11 +- src/elements/target.rs | 28 ++-- src/elements/timestamp.rs | 25 ++-- src/elements/title.rs | 51 +++---- src/parse/combinators.rs | 59 +++----- src/parsers.rs | 7 +- 24 files changed, 507 insertions(+), 656 deletions(-) diff --git a/src/elements/block.rs b/src/elements/block.rs index 5498cb5..f138950 100644 --- a/src/elements/block.rs +++ b/src/elements/block.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::tag_no_case, character::complete::{alpha1, space0}, - error::ParseError, sequence::preceded, IResult, }; @@ -11,136 +10,6 @@ use nom::{ use crate::elements::Element; use crate::parse::combinators::{blank_lines_count, line, lines_till}; -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct RawBlock<'a> { - pub name: &'a str, - pub arguments: &'a str, - - pub pre_blank: usize, - pub contents: &'a str, - pub contents_without_blank_lines: &'a str, - - pub post_blank: usize, -} - -impl<'a> RawBlock<'a> { - pub fn parse(input: &'a str) -> Option<(&str, RawBlock)> { - Self::parse_internal::<()>(input).ok() - } - - fn parse_internal(input: &'a str) -> IResult<&str, RawBlock, E> - where - E: ParseError<&'a str>, - { - let (input, _) = space0(input)?; - let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?; - let (input, arguments) = line(input)?; - let end_line = format!("#+END_{}", name); - let (input, contents) = - lines_till(|line| line.trim().eq_ignore_ascii_case(&end_line))(input)?; - let (contents_without_blank_lines, pre_blank) = blank_lines_count(contents)?; - let (input, post_blank) = blank_lines_count(input)?; - - Ok(( - input, - RawBlock { - name, - contents, - arguments: arguments.trim(), - pre_blank, - contents_without_blank_lines, - post_blank, - }, - )) - } - - pub fn into_element(self) -> (Element<'a>, &'a str) { - let RawBlock { - name, - contents, - arguments, - pre_blank, - contents_without_blank_lines, - post_blank, - } = self; - - let arguments: Option> = if arguments.is_empty() { - None - } else { - Some(arguments.into()) - }; - - let element = match &*name.to_uppercase() { - "CENTER" => CenterBlock { - parameters: arguments, - pre_blank, - post_blank, - } - .into(), - "QUOTE" => QuoteBlock { - parameters: arguments, - pre_blank, - post_blank, - } - .into(), - "VERSE" => VerseBlock { - parameters: arguments, - pre_blank, - post_blank, - } - .into(), - "COMMENT" => CommentBlock { - data: arguments, - contents: contents.into(), - post_blank, - } - .into(), - "EXAMPLE" => ExampleBlock { - data: arguments, - contents: contents.into(), - post_blank, - } - .into(), - "EXPORT" => ExportBlock { - data: arguments.unwrap_or_default(), - contents: contents.into(), - post_blank, - } - .into(), - "SRC" => { - let (language, arguments) = match &arguments { - Some(Cow::Borrowed(args)) => { - let (language, arguments) = - args.split_at(args.find(' ').unwrap_or_else(|| args.len())); - (language.into(), arguments.into()) - } - None => (Cow::Borrowed(""), Cow::Borrowed("")), - _ => unreachable!( - "`parse_block_element` returns `Some(Cow::Borrowed)` or `None`" - ), - }; - SourceBlock { - arguments, - language, - contents: contents.into(), - post_blank, - } - .into() - } - _ => SpecialBlock { - parameters: arguments, - name: name.into(), - pre_blank, - post_blank, - } - .into(), - }; - - (element, contents_without_blank_lines) - } -} - /// Special Block Element #[derive(Debug, Clone)] #[cfg_attr(test, derive(PartialEq))] @@ -351,16 +220,140 @@ impl SourceBlock<'_> { // TODO: fn retain_labels() -> bool { } } +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub(crate) struct RawBlock<'a> { + pub name: &'a str, + pub arguments: &'a str, + + pub pre_blank: usize, + pub contents: &'a str, + pub contents_without_blank_lines: &'a str, + + pub post_blank: usize, +} + +impl<'a> RawBlock<'a> { + pub fn parse(input: &str) -> Option<(&str, RawBlock)> { + parse_internal(input).ok() + } + + pub fn into_element(self) -> (Element<'a>, &'a str) { + let RawBlock { + name, + contents, + arguments, + pre_blank, + contents_without_blank_lines, + post_blank, + } = self; + + let arguments: Option> = if arguments.is_empty() { + None + } else { + Some(arguments.into()) + }; + + let element = match &*name.to_uppercase() { + "CENTER" => CenterBlock { + parameters: arguments, + pre_blank, + post_blank, + } + .into(), + "QUOTE" => QuoteBlock { + parameters: arguments, + pre_blank, + post_blank, + } + .into(), + "VERSE" => VerseBlock { + parameters: arguments, + pre_blank, + post_blank, + } + .into(), + "COMMENT" => CommentBlock { + data: arguments, + contents: contents.into(), + post_blank, + } + .into(), + "EXAMPLE" => ExampleBlock { + data: arguments, + contents: contents.into(), + post_blank, + } + .into(), + "EXPORT" => ExportBlock { + data: arguments.unwrap_or_default(), + contents: contents.into(), + post_blank, + } + .into(), + "SRC" => { + let (language, arguments) = match &arguments { + Some(Cow::Borrowed(args)) => { + let (language, arguments) = + args.split_at(args.find(' ').unwrap_or_else(|| args.len())); + (language.into(), arguments.into()) + } + None => (Cow::Borrowed(""), Cow::Borrowed("")), + _ => unreachable!( + "`parse_block_element` returns `Some(Cow::Borrowed)` or `None`" + ), + }; + SourceBlock { + arguments, + language, + contents: contents.into(), + post_blank, + } + .into() + } + _ => SpecialBlock { + parameters: arguments, + name: name.into(), + pre_blank, + post_blank, + } + .into(), + }; + + (element, contents_without_blank_lines) + } +} + +fn parse_internal(input: &str) -> IResult<&str, RawBlock, ()> { + let (input, _) = space0(input)?; + let (input, name) = preceded(tag_no_case("#+BEGIN_"), alpha1)(input)?; + let (input, arguments) = line(input)?; + let end_line = format!("#+END_{}", name); + let (input, contents) = lines_till(|line| line.trim().eq_ignore_ascii_case(&end_line))(input)?; + let (contents_without_blank_lines, pre_blank) = blank_lines_count(contents)?; + let (input, post_blank) = blank_lines_count(input)?; + + Ok(( + input, + RawBlock { + name, + contents, + arguments: arguments.trim(), + pre_blank, + contents_without_blank_lines, + post_blank, + }, + )) +} + #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - RawBlock::parse_internal::>( + RawBlock::parse( r#"#+BEGIN_SRC #+END_SRC"# ), - Ok(( + Some(( "", RawBlock { contents: "", @@ -374,11 +367,11 @@ fn parse() { ); assert_eq!( - RawBlock::parse_internal::>( + RawBlock::parse( r#"#+begin_src #+end_src"# ), - Ok(( + Some(( "", RawBlock { contents: "", @@ -392,14 +385,14 @@ fn parse() { ); assert_eq!( - RawBlock::parse_internal::>( + RawBlock::parse( r#"#+BEGIN_SRC javascript console.log('Hello World!'); #+END_SRC "# ), - Ok(( + Some(( "", RawBlock { contents: "console.log('Hello World!');\n", diff --git a/src/elements/clock.rs b/src/elements/clock.rs index 5a589b5..c489a88 100644 --- a/src/elements/clock.rs +++ b/src/elements/clock.rs @@ -4,7 +4,6 @@ use nom::{ bytes::complete::tag, character::complete::{char, digit1, space0}, combinator::recognize, - error::ParseError, sequence::separated_pair, IResult, }; @@ -50,7 +49,7 @@ pub enum Clock<'a> { impl Clock<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, Clock)> { - parse_clock::<()>(input).ok() + parse_internal(input).ok() } pub fn into_onwed(self) -> Clock<'static> { @@ -137,7 +136,7 @@ impl Clock<'_> { } } -fn parse_clock<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Clock, E> { +fn parse_internal(input: &str) -> IResult<&str, Clock, ()> { let (input, _) = space0(input)?; let (input, _) = tag("CLOCK:")(input)?; let (input, _) = space0(input)?; @@ -193,11 +192,9 @@ fn parse_clock<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Cloc #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_clock::>("CLOCK: [2003-09-16 Tue 09:39]"), - Ok(( + Clock::parse("CLOCK: [2003-09-16 Tue 09:39]"), + Some(( "", Clock::Running { start: Datetime { @@ -215,10 +212,8 @@ fn parse() { )) ); assert_eq!( - parse_clock::>( - "CLOCK: [2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39] => 1:00\n\n" - ), - Ok(( + Clock::parse("CLOCK: [2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39] => 1:00\n\n"), + Some(( "", Clock::Closed { start: Datetime { diff --git a/src/elements/comment.rs b/src/elements/comment.rs index baa9b0e..d6d414d 100644 --- a/src/elements/comment.rs +++ b/src/elements/comment.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use nom::{ - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, Err, IResult, }; @@ -19,32 +19,7 @@ pub struct Comment<'a> { impl Comment<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, Comment)> { - Self::parse_internal::<()>(input).ok() - } - - fn parse_internal<'a, E>(input: &'a str) -> IResult<&str, Comment, E> - where - E: ParseError<&'a str>, - { - let (input, value) = lines_while(|line| { - let line = line.trim_start(); - line == "#" || line.starts_with("# ") - })(input)?; - - if value.is_empty() { - // TODO: better error kind - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0))); - } - - let (input, post_blank) = blank_lines_count(input)?; - - Ok(( - input, - Comment { - value: value.into(), - post_blank, - }, - )) + parse_internal(input).ok() } pub fn into_owned(self) -> Comment<'static> { @@ -54,3 +29,25 @@ impl Comment<'_> { } } } + +fn parse_internal(input: &str) -> IResult<&str, Comment, ()> { + let (input, value) = lines_while(|line| { + let line = line.trim_start(); + line == "#" || line.starts_with("# ") + })(input)?; + + if value.is_empty() { + // TODO: better error kind + return Err(Err::Error(make_error(input, ErrorKind::Many0))); + } + + let (input, post_blank) = blank_lines_count(input)?; + + Ok(( + input, + Comment { + value: value.into(), + post_blank, + }, + )) +} diff --git a/src/elements/cookie.rs b/src/elements/cookie.rs index f88f672..59dd012 100644 --- a/src/elements/cookie.rs +++ b/src/elements/cookie.rs @@ -5,7 +5,6 @@ use nom::{ bytes::complete::tag, character::complete::digit0, combinator::recognize, - error::ParseError, sequence::{delimited, pair, separated_pair}, IResult, }; @@ -21,7 +20,7 @@ pub struct Cookie<'a> { impl Cookie<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, Cookie)> { - parse_cookie::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> Cookie<'static> { @@ -32,7 +31,7 @@ impl Cookie<'_> { } #[inline] -fn parse_cookie<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Cookie, E> { +fn parse_internal(input: &str) -> IResult<&str, Cookie, ()> { let (input, value) = recognize(delimited( tag("["), alt(( @@ -52,11 +51,9 @@ fn parse_cookie<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Coo #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_cookie::>("[1/10]"), - Ok(( + Cookie::parse("[1/10]"), + Some(( "", Cookie { value: "[1/10]".into() @@ -64,8 +61,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[1/1000]"), - Ok(( + Cookie::parse("[1/1000]"), + Some(( "", Cookie { value: "[1/1000]".into() @@ -73,8 +70,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[10%]"), - Ok(( + Cookie::parse("[10%]"), + Some(( "", Cookie { value: "[10%]".into() @@ -82,8 +79,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[%]"), - Ok(( + Cookie::parse("[%]"), + Some(( "", Cookie { value: "[%]".into() @@ -91,8 +88,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[/]"), - Ok(( + Cookie::parse("[/]"), + Some(( "", Cookie { value: "[/]".into() @@ -100,8 +97,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[100/]"), - Ok(( + Cookie::parse("[100/]"), + Some(( "", Cookie { value: "[100/]".into() @@ -109,8 +106,8 @@ fn parse() { )) ); assert_eq!( - parse_cookie::>("[/100]"), - Ok(( + Cookie::parse("[/100]"), + Some(( "", Cookie { value: "[/100]".into() @@ -118,8 +115,8 @@ fn parse() { )) ); - assert!(parse_cookie::>("[10% ]").is_err()); - assert!(parse_cookie::>("[1//100]").is_err()); - assert!(parse_cookie::>("[1\\100]").is_err()); - assert!(parse_cookie::>("[10%%]").is_err()); + assert!(Cookie::parse("[10% ]").is_none()); + assert!(Cookie::parse("[1//100]").is_none()); + assert!(Cookie::parse("[1\\100]").is_none()); + assert!(Cookie::parse("[10%%]").is_none()); } diff --git a/src/elements/drawer.rs b/src/elements/drawer.rs index ab7e9b2..20bb956 100644 --- a/src/elements/drawer.rs +++ b/src/elements/drawer.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_while1}, character::complete::space0, - error::ParseError, sequence::delimited, IResult, }; @@ -27,7 +26,7 @@ pub struct Drawer<'a> { impl Drawer<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, (Drawer, &str))> { - parse_drawer::<()>(input).ok() + parse_drawer(input).ok() } pub fn into_owned(self) -> Drawer<'static> { @@ -40,10 +39,7 @@ impl Drawer<'_> { } #[inline] -pub fn parse_drawer<'a, E>(input: &'a str) -> IResult<&str, (Drawer, &str), E> -where - E: ParseError<&'a str>, -{ +pub fn parse_drawer(input: &str) -> IResult<&str, (Drawer, &str), ()> { let (input, (mut drawer, content)) = parse_drawer_without_blank(input)?; let (content, blank) = blank_lines_count(content)?; @@ -55,10 +51,7 @@ where Ok((input, (drawer, content))) } -pub fn parse_drawer_without_blank<'a, E>(input: &'a str) -> IResult<&str, (Drawer, &str), E> -where - E: ParseError<&'a str>, -{ +pub fn parse_drawer_without_blank(input: &str) -> IResult<&str, (Drawer, &str), ()> { let (input, _) = space0(input)?; let (input, name) = delimited( tag(":"), @@ -83,10 +76,8 @@ where #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_drawer::>( + parse_drawer( r#":PROPERTIES: :CUSTOM_ID: id :END:"# @@ -104,7 +95,7 @@ fn parse() { )) ); assert_eq!( - parse_drawer::>( + parse_drawer( r#":PROPERTIES: @@ -126,5 +117,5 @@ fn parse() { ); // https://github.com/PoiScript/orgize/issues/9 - assert!(parse_drawer::<()>(":SPAGHETTI:\n").is_err()); + assert!(parse_drawer(":SPAGHETTI:\n").is_err()); } diff --git a/src/elements/dyn_block.rs b/src/elements/dyn_block.rs index f2e05e3..c74e7c1 100644 --- a/src/elements/dyn_block.rs +++ b/src/elements/dyn_block.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::tag_no_case, character::complete::{alpha1, space0, space1}, - error::ParseError, IResult, }; @@ -29,7 +28,7 @@ pub struct DynBlock<'a> { impl DynBlock<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, (DynBlock, &str))> { - parse_dyn_block::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> DynBlock<'static> { @@ -43,10 +42,7 @@ impl DynBlock<'_> { } #[inline] -fn parse_dyn_block<'a, E>(input: &'a str) -> IResult<&str, (DynBlock, &str), E> -where - E: ParseError<&'a str>, -{ +fn parse_internal(input: &str) -> IResult<&str, (DynBlock, &str), ()> { let (input, _) = space0(input)?; let (input, _) = tag_no_case("#+BEGIN:")(input)?; let (input, _) = space1(input)?; @@ -76,11 +72,9 @@ where #[test] fn parse() { - use nom::error::VerboseError; - // TODO: testing assert_eq!( - parse_dyn_block::>( + DynBlock::parse( r#"#+BEGIN: clocktable :scope file @@ -89,7 +83,7 @@ CONTENTS "# ), - Ok(( + Some(( "", ( DynBlock { diff --git a/src/elements/fixed_width.rs b/src/elements/fixed_width.rs index fba1d4f..ae06677 100644 --- a/src/elements/fixed_width.rs +++ b/src/elements/fixed_width.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use nom::{ - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, Err, IResult, }; @@ -20,32 +20,7 @@ pub struct FixedWidth<'a> { impl FixedWidth<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, FixedWidth)> { - Self::parse_internal::<()>(input).ok() - } - - fn parse_internal<'a, E>(input: &'a str) -> IResult<&str, FixedWidth, E> - where - E: ParseError<&'a str>, - { - let (input, value) = lines_while(|line| { - let line = line.trim_start(); - line == ":" || line.starts_with(": ") - })(input)?; - - if value.is_empty() { - // TODO: better error kind - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0))); - } - - let (input, post_blank) = blank_lines_count(input)?; - - Ok(( - input, - FixedWidth { - value: value.into(), - post_blank, - }, - )) + parse_internal(input).ok() } pub fn into_owned(self) -> FixedWidth<'static> { @@ -56,6 +31,28 @@ impl FixedWidth<'_> { } } +fn parse_internal(input: &str) -> IResult<&str, FixedWidth, ()> { + let (input, value) = lines_while(|line| { + let line = line.trim_start(); + line == ":" || line.starts_with(": ") + })(input)?; + + if value.is_empty() { + // TODO: better error kind + return Err(Err::Error(make_error(input, ErrorKind::Many0))); + } + + let (input, post_blank) = blank_lines_count(input)?; + + Ok(( + input, + FixedWidth { + value: value.into(), + post_blank, + }, + )) +} + #[test] fn parse() { assert_eq!( diff --git a/src/elements/fn_def.rs b/src/elements/fn_def.rs index f7550d8..2c91f16 100644 --- a/src/elements/fn_def.rs +++ b/src/elements/fn_def.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_while1}, - error::ParseError, sequence::delimited, IResult, }; @@ -23,33 +22,7 @@ pub struct FnDef<'a> { impl FnDef<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, (FnDef, &str))> { - Self::parse_internal::<()>(input).ok() - } - - fn parse_internal<'a, E>(input: &'a str) -> IResult<&str, (FnDef, &str), E> - where - E: ParseError<&'a str>, - { - let (input, label) = delimited( - tag("[fn:"), - take_while1(|c: char| c.is_ascii_alphanumeric() || c == '-' || c == '_'), - tag("]"), - )(input)?; - - let (input, content) = line(input)?; - - let (input, post_blank) = blank_lines_count(input)?; - - Ok(( - input, - ( - FnDef { - label: label.into(), - post_blank, - }, - content, - ), - )) + parse_internal(input).ok() } pub fn into_owned(self) -> FnDef<'static> { @@ -60,13 +33,34 @@ impl FnDef<'_> { } } +fn parse_internal(input: &str) -> IResult<&str, (FnDef, &str), ()> { + let (input, label) = delimited( + tag("[fn:"), + take_while1(|c: char| c.is_ascii_alphanumeric() || c == '-' || c == '_'), + tag("]"), + )(input)?; + + let (input, content) = line(input)?; + + let (input, post_blank) = blank_lines_count(input)?; + + Ok(( + input, + ( + FnDef { + label: label.into(), + post_blank, + }, + content, + ), + )) +} + #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - FnDef::parse_internal::>("[fn:1] https://orgmode.org"), - Ok(( + FnDef::parse("[fn:1] https://orgmode.org"), + Some(( "", ( FnDef { @@ -78,8 +72,8 @@ fn parse() { )) ); assert_eq!( - FnDef::parse_internal::>("[fn:word_1] https://orgmode.org"), - Ok(( + FnDef::parse("[fn:word_1] https://orgmode.org"), + Some(( "", ( FnDef { @@ -91,8 +85,8 @@ fn parse() { )) ); assert_eq!( - FnDef::parse_internal::>("[fn:WORD-1] https://orgmode.org"), - Ok(( + FnDef::parse("[fn:WORD-1] https://orgmode.org"), + Some(( "", ( FnDef { @@ -104,8 +98,8 @@ fn parse() { )) ); assert_eq!( - FnDef::parse_internal::>("[fn:WORD]"), - Ok(( + FnDef::parse("[fn:WORD]"), + Some(( "", ( FnDef { @@ -117,7 +111,7 @@ fn parse() { )) ); - assert!(FnDef::parse_internal::>("[fn:] https://orgmode.org").is_err()); - assert!(FnDef::parse_internal::>("[fn:wor d] https://orgmode.org").is_err()); - assert!(FnDef::parse_internal::>("[fn:WORD https://orgmode.org").is_err()); + assert!(FnDef::parse("[fn:] https://orgmode.org").is_none()); + assert!(FnDef::parse("[fn:wor d] https://orgmode.org").is_none()); + assert!(FnDef::parse("[fn:WORD https://orgmode.org").is_none()); } diff --git a/src/elements/fn_ref.rs b/src/elements/fn_ref.rs index 6185bc4..c03253e 100644 --- a/src/elements/fn_ref.rs +++ b/src/elements/fn_ref.rs @@ -4,7 +4,7 @@ use memchr::memchr2_iter; use nom::{ bytes::complete::{tag, take_while}, combinator::opt, - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, sequence::preceded, Err, IResult, }; @@ -22,7 +22,7 @@ pub struct FnRef<'a> { impl FnRef<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, FnRef)> { - parse_fn_ref::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> FnRef<'static> { @@ -34,7 +34,7 @@ impl FnRef<'_> { } #[inline] -fn parse_fn_ref<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, FnRef, E> { +fn parse_internal(input: &str) -> IResult<&str, FnRef, ()> { let (input, _) = tag("[fn:")(input)?; let (input, label) = take_while(|c: char| c.is_ascii_alphanumeric() || c == '-' || c == '_')(input)?; @@ -50,7 +50,7 @@ fn parse_fn_ref<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, FnR )) } -fn balanced_brackets<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, &str, E> { +fn balanced_brackets(input: &str) -> IResult<&str, &str, ()> { let mut pairs = 1; for i in memchr2_iter(b'[', b']', input.as_bytes()) { if input.as_bytes()[i] == b'[' { @@ -61,16 +61,14 @@ fn balanced_brackets<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str return Ok((&input[i..], &input[0..i])); } } - Err(Err::Error(E::from_error_kind(input, ErrorKind::Tag))) + Err(Err::Error(make_error(input, ErrorKind::Tag))) } #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_fn_ref::>("[fn:1]"), - Ok(( + FnRef::parse("[fn:1]"), + Some(( "", FnRef { label: "1".into(), @@ -79,8 +77,8 @@ fn parse() { )) ); assert_eq!( - parse_fn_ref::>("[fn:1:2]"), - Ok(( + FnRef::parse("[fn:1:2]"), + Some(( "", FnRef { label: "1".into(), @@ -89,8 +87,8 @@ fn parse() { )) ); assert_eq!( - parse_fn_ref::>("[fn::2]"), - Ok(( + FnRef::parse("[fn::2]"), + Some(( "", FnRef { label: "".into(), @@ -99,8 +97,8 @@ fn parse() { )) ); assert_eq!( - parse_fn_ref::>("[fn::[]]"), - Ok(( + FnRef::parse("[fn::[]]"), + Some(( "", FnRef { label: "".into(), @@ -109,5 +107,5 @@ fn parse() { )) ); - assert!(parse_fn_ref::>("[fn::[]").is_err()); + assert!(FnRef::parse("[fn::[]").is_none()); } diff --git a/src/elements/inline_call.rs b/src/elements/inline_call.rs index 7242673..8878beb 100644 --- a/src/elements/inline_call.rs +++ b/src/elements/inline_call.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_till}, combinator::opt, - error::ParseError, sequence::{delimited, preceded}, IResult, }; @@ -27,7 +26,7 @@ pub struct InlineCall<'a> { impl InlineCall<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, InlineCall)> { - parse_inline_call::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> InlineCall<'static> { @@ -41,7 +40,7 @@ impl InlineCall<'_> { } #[inline] -fn parse_inline_call<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, InlineCall, E> { +fn parse_internal(input: &str) -> IResult<&str, InlineCall, ()> { let (input, name) = preceded( tag("call_"), take_till(|c| c == '[' || c == '\n' || c == '(' || c == ')'), @@ -72,11 +71,9 @@ fn parse_inline_call<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_inline_call::>("call_square(4)"), - Ok(( + InlineCall::parse("call_square(4)"), + Some(( "", InlineCall { name: "square".into(), @@ -87,8 +84,8 @@ fn parse() { )) ); assert_eq!( - parse_inline_call::>("call_square[:results output](4)"), - Ok(( + InlineCall::parse("call_square[:results output](4)"), + Some(( "", InlineCall { name: "square".into(), @@ -99,8 +96,8 @@ fn parse() { )) ); assert_eq!( - parse_inline_call::>("call_square(4)[:results html]"), - Ok(( + InlineCall::parse("call_square(4)[:results html]"), + Some(( "", InlineCall { name: "square".into(), @@ -111,8 +108,8 @@ fn parse() { )) ); assert_eq!( - parse_inline_call::>("call_square[:results output](4)[:results html]"), - Ok(( + InlineCall::parse("call_square[:results output](4)[:results html]"), + Some(( "", InlineCall { name: "square".into(), diff --git a/src/elements/inline_src.rs b/src/elements/inline_src.rs index cbd8888..f04d31a 100644 --- a/src/elements/inline_src.rs +++ b/src/elements/inline_src.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_till, take_while1}, combinator::opt, - error::ParseError, sequence::delimited, IResult, }; @@ -24,7 +23,7 @@ pub struct InlineSrc<'a> { impl InlineSrc<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, InlineSrc)> { - parse_inline_src::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> InlineSrc<'static> { @@ -37,7 +36,7 @@ impl InlineSrc<'_> { } #[inline] -fn parse_inline_src<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, InlineSrc, E> { +fn parse_internal(input: &str) -> IResult<&str, InlineSrc, ()> { let (input, _) = tag("src_")(input)?; let (input, lang) = take_while1(|c: char| !c.is_ascii_whitespace() && c != '[' && c != '{')(input)?; @@ -60,11 +59,9 @@ fn parse_inline_src<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_inline_src::>("src_C{int a = 0;}"), - Ok(( + InlineSrc::parse("src_C{int a = 0;}"), + Some(( "", InlineSrc { lang: "C".into(), @@ -74,8 +71,8 @@ fn parse() { )) ); assert_eq!( - parse_inline_src::>("src_xml[:exports code]{text}"), - Ok(( + InlineSrc::parse("src_xml[:exports code]{text}"), + Some(( "", InlineSrc { lang: "xml".into(), @@ -85,11 +82,7 @@ fn parse() { )) ); - assert!( - parse_inline_src::>("src_xml[:exports code]{text").is_err() - ); - assert!( - parse_inline_src::>("src_[:exports code]{text}").is_err() - ); - assert!(parse_inline_src::>("src_xml[:exports code]").is_err()); + assert!(InlineSrc::parse("src_xml[:exports code]{text").is_none()); + assert!(InlineSrc::parse("src_[:exports code]{text}").is_none()); + assert!(InlineSrc::parse("src_xml[:exports code]").is_none()); } diff --git a/src/elements/keyword.rs b/src/elements/keyword.rs index 2ac07d4..af8f8d9 100644 --- a/src/elements/keyword.rs +++ b/src/elements/keyword.rs @@ -4,7 +4,6 @@ use nom::{ bytes::complete::{tag, take_till}, character::complete::space0, combinator::opt, - error::ParseError, sequence::delimited, IResult, }; @@ -12,74 +11,6 @@ use nom::{ use crate::elements::Element; use crate::parse::combinators::{blank_lines_count, line}; -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq))] -pub(crate) struct RawKeyword<'a> { - pub key: &'a str, - pub value: &'a str, - pub optional: Option<&'a str>, - pub post_blank: usize, -} - -impl<'a> RawKeyword<'a> { - pub fn parse(input: &'a str) -> Option<(&str, RawKeyword)> { - Self::parse_internal::<()>(input).ok() - } - - fn parse_internal(input: &'a str) -> IResult<&str, RawKeyword, E> - where - E: ParseError<&'a str>, - { - let (input, _) = space0(input)?; - let (input, _) = tag("#+")(input)?; - let (input, key) = - take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?; - let (input, optional) = opt(delimited( - tag("["), - take_till(|c| c == ']' || c == '\n'), - tag("]"), - ))(input)?; - let (input, _) = tag(":")(input)?; - let (input, value) = line(input)?; - let (input, post_blank) = blank_lines_count(input)?; - - Ok(( - input, - RawKeyword { - key, - optional, - value: value.trim(), - post_blank, - }, - )) - } - - pub fn into_element(self) -> Element<'a> { - let RawKeyword { - key, - value, - optional, - post_blank, - } = self; - - if (&*key).eq_ignore_ascii_case("CALL") { - BabelCall { - value: value.into(), - post_blank, - } - .into() - } else { - Keyword { - key: key.into(), - optional: optional.map(Into::into), - value: value.into(), - post_blank, - } - .into() - } - } -} - /// Keyword Element #[cfg_attr(test, derive(PartialEq))] #[cfg_attr(feature = "ser", derive(serde::Serialize))] @@ -128,13 +59,75 @@ impl BabelCall<'_> { } } +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq))] +pub(crate) struct RawKeyword<'a> { + pub key: &'a str, + pub value: &'a str, + pub optional: Option<&'a str>, + pub post_blank: usize, +} + +impl<'a> RawKeyword<'a> { + pub fn parse(input: &str) -> Option<(&str, RawKeyword)> { + parse_internal(input).ok() + } + + pub fn into_element(self) -> Element<'a> { + let RawKeyword { + key, + value, + optional, + post_blank, + } = self; + + if (&*key).eq_ignore_ascii_case("CALL") { + BabelCall { + value: value.into(), + post_blank, + } + .into() + } else { + Keyword { + key: key.into(), + optional: optional.map(Into::into), + value: value.into(), + post_blank, + } + .into() + } + } +} + +fn parse_internal(input: &str) -> IResult<&str, RawKeyword, ()> { + let (input, _) = space0(input)?; + let (input, _) = tag("#+")(input)?; + let (input, key) = take_till(|c: char| c.is_ascii_whitespace() || c == ':' || c == '[')(input)?; + let (input, optional) = opt(delimited( + tag("["), + take_till(|c| c == ']' || c == '\n'), + tag("]"), + ))(input)?; + let (input, _) = tag(":")(input)?; + let (input, value) = line(input)?; + let (input, post_blank) = blank_lines_count(input)?; + + Ok(( + input, + RawKeyword { + key, + optional, + value: value.trim(), + post_blank, + }, + )) +} + #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - RawKeyword::parse_internal::>("#+KEY:"), - Ok(( + RawKeyword::parse("#+KEY:"), + Some(( "", RawKeyword { key: "KEY", @@ -145,8 +138,8 @@ fn parse() { )) ); assert_eq!( - RawKeyword::parse_internal::>("#+KEY: VALUE"), - Ok(( + RawKeyword::parse("#+KEY: VALUE"), + Some(( "", RawKeyword { key: "KEY", @@ -157,8 +150,8 @@ fn parse() { )) ); assert_eq!( - RawKeyword::parse_internal::>("#+K_E_Y: VALUE"), - Ok(( + RawKeyword::parse("#+K_E_Y: VALUE"), + Some(( "", RawKeyword { key: "K_E_Y", @@ -169,8 +162,8 @@ fn parse() { )) ); assert_eq!( - RawKeyword::parse_internal::>("#+KEY:VALUE\n"), - Ok(( + RawKeyword::parse("#+KEY:VALUE\n"), + Some(( "", RawKeyword { key: "KEY", @@ -180,12 +173,12 @@ fn parse() { } )) ); - assert!(RawKeyword::parse_internal::>("#+KE Y: VALUE").is_err()); - assert!(RawKeyword::parse_internal::>("#+ KEY: VALUE").is_err()); + assert!(RawKeyword::parse("#+KE Y: VALUE").is_none()); + assert!(RawKeyword::parse("#+ KEY: VALUE").is_none()); assert_eq!( - RawKeyword::parse_internal::>("#+RESULTS:"), - Ok(( + RawKeyword::parse("#+RESULTS:"), + Some(( "", RawKeyword { key: "RESULTS", @@ -197,8 +190,8 @@ fn parse() { ); assert_eq!( - RawKeyword::parse_internal::>("#+ATTR_LATEX: :width 5cm\n"), - Ok(( + RawKeyword::parse("#+ATTR_LATEX: :width 5cm\n"), + Some(( "", RawKeyword { key: "ATTR_LATEX", @@ -210,8 +203,8 @@ fn parse() { ); assert_eq!( - RawKeyword::parse_internal::>("#+CALL: double(n=4)"), - Ok(( + RawKeyword::parse("#+CALL: double(n=4)"), + Some(( "", RawKeyword { key: "CALL", @@ -223,10 +216,8 @@ fn parse() { ); assert_eq!( - RawKeyword::parse_internal::>( - "#+CAPTION[Short caption]: Longer caption." - ), - Ok(( + RawKeyword::parse("#+CAPTION[Short caption]: Longer caption."), + Some(( "", RawKeyword { key: "CAPTION", diff --git a/src/elements/link.rs b/src/elements/link.rs index 310e35c..b0bb08d 100644 --- a/src/elements/link.rs +++ b/src/elements/link.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_while}, combinator::opt, - error::ParseError, sequence::delimited, IResult, }; @@ -22,7 +21,7 @@ pub struct Link<'a> { impl Link<'_> { #[inline] pub(crate) fn parse(input: &str) -> Option<(&str, Link)> { - parse_link::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> Link<'static> { @@ -34,7 +33,7 @@ impl Link<'_> { } #[inline] -fn parse_link<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Link, E> { +fn parse_internal(input: &str) -> IResult<&str, Link, ()> { let (input, path) = delimited( tag("[["), take_while(|c: char| c != '<' && c != '>' && c != '\n' && c != ']'), @@ -57,11 +56,9 @@ fn parse_link<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Link, #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_link::>("[[#id]]"), - Ok(( + Link::parse("[[#id]]"), + Some(( "", Link { path: "#id".into(), @@ -70,8 +67,8 @@ fn parse() { )) ); assert_eq!( - parse_link::>("[[#id][desc]]"), - Ok(( + Link::parse("[[#id][desc]]"), + Some(( "", Link { path: "#id".into(), @@ -79,5 +76,5 @@ fn parse() { } )) ); - assert!(parse_link::>("[[#id][desc]").is_err()); + assert!(Link::parse("[[#id][desc]").is_none()); } diff --git a/src/elements/list.rs b/src/elements/list.rs index 302ab77..3b49852 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -7,7 +7,6 @@ use nom::{ bytes::complete::tag, character::complete::{digit1, space0}, combinator::{map, recognize}, - error::ParseError, sequence::terminated, IResult, }; @@ -45,7 +44,7 @@ pub struct ListItem<'a> { impl ListItem<'_> { #[inline] pub(crate) fn parse(input: &str) -> Option<(&str, (ListItem, &str))> { - list_item::<()>(input).ok() + list_item(input).ok() } pub fn into_owned(self) -> ListItem<'static> { @@ -57,7 +56,7 @@ impl ListItem<'_> { } } -fn list_item<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, (ListItem, &str), E> { +fn list_item(input: &str) -> IResult<&str, (ListItem, &str), ()> { let (input, indent) = map(space0, |s: &str| s.len())(input)?; let (input, bullet) = recognize(alt(( tag("+ "), @@ -122,10 +121,8 @@ fn list_item_contents(input: &str, indent: usize) -> (&str, &str) { #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - list_item::>( + list_item( r#"+ item1 + item2"# ), @@ -143,7 +140,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"* item1 * item2"# @@ -163,7 +160,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"* item1 @@ -185,7 +182,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"* item1 "# @@ -205,7 +202,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"+ item1 + item2 "# @@ -225,7 +222,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"+ item1 + item2 @@ -249,7 +246,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#" + item1 + item2"# @@ -269,7 +266,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#" 1. item1 2. item2 3. item3"# @@ -289,7 +286,7 @@ fn parse() { )) ); assert_eq!( - list_item::>( + list_item( r#"+ 1 - 2 diff --git a/src/elements/macros.rs b/src/elements/macros.rs index 1e35ede..8568d5b 100644 --- a/src/elements/macros.rs +++ b/src/elements/macros.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take, take_until, take_while1}, combinator::{opt, verify}, - error::ParseError, sequence::delimited, IResult, }; @@ -22,7 +21,7 @@ pub struct Macros<'a> { impl Macros<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, Macros)> { - parse_macros::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> Macros<'static> { @@ -34,7 +33,7 @@ impl Macros<'_> { } #[inline] -fn parse_macros<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Macros, E> { +fn parse_internal(input: &str) -> IResult<&str, Macros, ()> { let (input, _) = tag("{{{")(input)?; let (input, name) = verify( take_while1(|c: char| c.is_ascii_alphanumeric() || c == '-' || c == '_'), @@ -53,12 +52,10 @@ fn parse_macros<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Mac } #[test] -fn parse() { - use nom::error::VerboseError; - +fn test() { assert_eq!( - parse_macros::>("{{{poem(red,blue)}}}"), - Ok(( + Macros::parse("{{{poem(red,blue)}}}"), + Some(( "", Macros { name: "poem".into(), @@ -67,8 +64,8 @@ fn parse() { )) ); assert_eq!( - parse_macros::>("{{{poem())}}}"), - Ok(( + Macros::parse("{{{poem())}}}"), + Some(( "", Macros { name: "poem".into(), @@ -77,8 +74,8 @@ fn parse() { )) ); assert_eq!( - parse_macros::>("{{{author}}}"), - Ok(( + Macros::parse("{{{author}}}"), + Some(( "", Macros { name: "author".into(), @@ -86,8 +83,9 @@ fn parse() { } )) ); - assert!(parse_macros::>("{{{0uthor}}}").is_err()); - assert!(parse_macros::>("{{{author}}").is_err()); - assert!(parse_macros::>("{{{poem(}}}").is_err()); - assert!(parse_macros::>("{{{poem)}}}").is_err()); + + assert!(Macros::parse("{{{0uthor}}}").is_none()); + assert!(Macros::parse("{{{author}}").is_none()); + assert!(Macros::parse("{{{poem(}}}").is_none()); + assert!(Macros::parse("{{{poem)}}}").is_none()); } diff --git a/src/elements/radio_target.rs b/src/elements/radio_target.rs index 18bad1f..fd529c7 100644 --- a/src/elements/radio_target.rs +++ b/src/elements/radio_target.rs @@ -1,7 +1,6 @@ use nom::{ bytes::complete::{tag, take_while}, combinator::verify, - error::ParseError, sequence::delimited, IResult, }; @@ -10,13 +9,11 @@ use nom::{ #[inline] pub fn parse_radio_target(input: &str) -> Option<(&str, &str)> { - parse_radio_target_internal::<()>(input).ok() + parse_internal(input).ok() } #[inline] -fn parse_radio_target_internal<'a, E: ParseError<&'a str>>( - input: &'a str, -) -> IResult<&str, &str, E> { +fn parse_internal(input: &str) -> IResult<&str, &str, ()> { let (input, contents) = delimited( tag("<<<"), verify( @@ -31,20 +28,13 @@ fn parse_radio_target_internal<'a, E: ParseError<&'a str>>( #[test] fn parse() { - use nom::error::VerboseError; + assert_eq!(parse_radio_target("<<>>"), Some(("", "target"))); + assert_eq!(parse_radio_target("<<>>"), Some(("", "tar get"))); - assert_eq!( - parse_radio_target_internal::>("<<>>"), - Ok(("", "target")) - ); - assert_eq!( - parse_radio_target_internal::>("<<>>"), - Ok(("", "tar get")) - ); - assert!(parse_radio_target_internal::>("<<>>").is_err()); - assert!(parse_radio_target_internal::>("<<< target>>>").is_err()); - assert!(parse_radio_target_internal::>("<<>>").is_err()); - assert!(parse_radio_target_internal::>("<<get>>>").is_err()); - assert!(parse_radio_target_internal::>("<<>>").is_err()); - assert!(parse_radio_target_internal::>("<<>").is_err()); + assert!(parse_radio_target("<<>>").is_none()); + assert!(parse_radio_target("<<< target>>>").is_none()); + assert!(parse_radio_target("<<>>").is_none()); + assert!(parse_radio_target("<<get>>>").is_none()); + assert!(parse_radio_target("<<>>").is_none()); + assert!(parse_radio_target("<<>").is_none()); } diff --git a/src/elements/rule.rs b/src/elements/rule.rs index ad83eed..b331746 100644 --- a/src/elements/rule.rs +++ b/src/elements/rule.rs @@ -1,6 +1,4 @@ -use nom::{ - bytes::complete::take_while_m_n, character::complete::space0, error::ParseError, IResult, -}; +use nom::{bytes::complete::take_while_m_n, character::complete::space0, IResult}; use crate::parse::combinators::{blank_lines_count, eol}; @@ -15,14 +13,11 @@ pub struct Rule { impl Rule { pub(crate) fn parse(input: &str) -> Option<(&str, Rule)> { - parse_rule::<()>(input).ok() + parse_internal(input).ok() } } -fn parse_rule<'a, E>(input: &'a str) -> IResult<&str, Rule, E> -where - E: ParseError<&'a str>, -{ +fn parse_internal(input: &str) -> IResult<&str, Rule, ()> { let (input, _) = space0(input)?; let (input, _) = take_while_m_n(5, usize::max_value(), |c| c == '-')(input)?; let (input, _) = eol(input)?; @@ -32,32 +27,22 @@ where #[test] fn parse() { - use nom::error::VerboseError; + assert_eq!(Rule::parse("-----"), Some(("", Rule { post_blank: 0 }))); + assert_eq!(Rule::parse("--------"), Some(("", Rule { post_blank: 0 }))); + assert_eq!( + Rule::parse("-----\n\n\n"), + Some(("", Rule { post_blank: 2 })) + ); + assert_eq!(Rule::parse("----- \n"), Some(("", Rule { post_blank: 0 }))); - assert_eq!( - parse_rule::>("-----"), - Ok(("", Rule { post_blank: 0 })) - ); - assert_eq!( - parse_rule::>("--------"), - Ok(("", Rule { post_blank: 0 })) - ); - assert_eq!( - parse_rule::>("-----\n\n\n"), - Ok(("", Rule { post_blank: 2 })) - ); - assert_eq!( - parse_rule::>("----- \n"), - Ok(("", Rule { post_blank: 0 })) - ); - assert!(parse_rule::>("").is_err()); - assert!(parse_rule::>("----").is_err()); - assert!(parse_rule::>("----").is_err()); - assert!(parse_rule::>("None----").is_err()); - assert!(parse_rule::>("None ----").is_err()); - assert!(parse_rule::>("None------").is_err()); - assert!(parse_rule::>("----None----").is_err()); - assert!(parse_rule::>("\t\t----").is_err()); - assert!(parse_rule::>("------None").is_err()); - assert!(parse_rule::>("----- None").is_err()); + assert!(Rule::parse("").is_none()); + assert!(Rule::parse("----").is_none()); + assert!(Rule::parse("----").is_none()); + assert!(Rule::parse("None----").is_none()); + assert!(Rule::parse("None ----").is_none()); + assert!(Rule::parse("None------").is_none()); + assert!(Rule::parse("----None----").is_none()); + assert!(Rule::parse("\t\t----").is_none()); + assert!(Rule::parse("------None").is_none()); + assert!(Rule::parse("----- None").is_none()); } diff --git a/src/elements/snippet.rs b/src/elements/snippet.rs index 73939e1..31e2117 100644 --- a/src/elements/snippet.rs +++ b/src/elements/snippet.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take, take_until, take_while1}, - error::ParseError, sequence::{delimited, separated_pair}, IResult, }; @@ -20,7 +19,7 @@ pub struct Snippet<'a> { impl Snippet<'_> { pub(crate) fn parse(input: &str) -> Option<(&str, Snippet)> { - parse_snippet::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> Snippet<'static> { @@ -32,7 +31,7 @@ impl Snippet<'_> { } #[inline] -fn parse_snippet<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Snippet, E> { +fn parse_internal(input: &str) -> IResult<&str, Snippet, ()> { let (input, (name, value)) = delimited( tag("@@"), separated_pair( @@ -54,11 +53,9 @@ fn parse_snippet<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Sn #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_snippet::>("@@html:@@"), - Ok(( + Snippet::parse("@@html:@@"), + Some(( "", Snippet { name: "html".into(), @@ -67,8 +64,8 @@ fn parse() { )) ); assert_eq!( - parse_snippet::>("@@latex:any arbitrary LaTeX code@@"), - Ok(( + Snippet::parse("@@latex:any arbitrary LaTeX code@@"), + Some(( "", Snippet { name: "latex".into(), @@ -77,8 +74,8 @@ fn parse() { )) ); assert_eq!( - parse_snippet::>("@@html:@@"), - Ok(( + Snippet::parse("@@html:@@"), + Some(( "", Snippet { name: "html".into(), @@ -87,8 +84,8 @@ fn parse() { )) ); assert_eq!( - parse_snippet::>("@@html:

@

@@"), - Ok(( + Snippet::parse("@@html:

@

@@"), + Some(( "", Snippet { name: "html".into(), @@ -96,7 +93,8 @@ fn parse() { } )) ); - assert!(parse_snippet::>("@@html:@").is_err()); - assert!(parse_snippet::>("@@html@@").is_err()); - assert!(parse_snippet::>("@@:@@").is_err()); + + assert!(Snippet::parse("@@html:@").is_none()); + assert!(Snippet::parse("@@html@@").is_none()); + assert!(Snippet::parse("@@:@@").is_none()); } diff --git a/src/elements/table.rs b/src/elements/table.rs index 56befb8..752083a 100644 --- a/src/elements/table.rs +++ b/src/elements/table.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use nom::{ - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, Err, IResult, }; @@ -35,13 +35,10 @@ pub enum Table<'a> { impl Table<'_> { pub fn parse_table_el(input: &str) -> Option<(&str, Table)> { - Self::parse_table_el_internal::<()>(input).ok() + Self::parse_table_el_internal(input).ok() } - fn parse_table_el_internal<'a, E>(input: &'a str) -> IResult<&str, Table, E> - where - E: ParseError<&'a str>, - { + fn parse_table_el_internal(input: &str) -> IResult<&str, Table, ()> { let (_, first_line) = line(input)?; let first_line = first_line.trim(); @@ -54,7 +51,7 @@ impl Table<'_> { .any(|&c| c != b'+' && c != b'-') { // TODO: better error kind - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0))); + return Err(Err::Error(make_error(input, ErrorKind::Many0))); } // Table.el tables end at the first line not starting with either a vertical line or a plus sign. diff --git a/src/elements/target.rs b/src/elements/target.rs index 4270498..b847b59 100644 --- a/src/elements/target.rs +++ b/src/elements/target.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use nom::{ bytes::complete::{tag, take_while}, combinator::verify, - error::ParseError, sequence::delimited, IResult, }; @@ -20,7 +19,7 @@ pub struct Target<'a> { impl Target<'_> { #[inline] pub(crate) fn parse(input: &str) -> Option<(&str, Target)> { - parse_target::<()>(input).ok() + parse_internal(input).ok() } pub fn into_owned(self) -> Target<'static> { @@ -31,7 +30,7 @@ impl Target<'_> { } #[inline] -fn parse_target<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Target, E> { +fn parse_internal(input: &str) -> IResult<&str, Target, ()> { let (input, target) = delimited( tag("<<"), verify( @@ -51,11 +50,9 @@ fn parse_target<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Tar #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_target::>("<>"), - Ok(( + Target::parse("<>"), + Some(( "", Target { target: "target".into() @@ -63,18 +60,19 @@ fn parse() { )) ); assert_eq!( - parse_target::>("<>"), - Ok(( + Target::parse("<>"), + Some(( "", Target { target: "tar get".into() } )) ); - assert!(parse_target::>("<>").is_err()); - assert!(parse_target::>("<< target>>").is_err()); - assert!(parse_target::>("<>").is_err()); - assert!(parse_target::>("<get>>").is_err()); - assert!(parse_target::>("<>").is_err()); - assert!(parse_target::>("<").is_err()); + + assert!(Target::parse("<>").is_none()); + assert!(Target::parse("<< target>>").is_none()); + assert!(Target::parse("<>").is_none()); + assert!(Target::parse("<get>>").is_none()); + assert!(Target::parse("<>").is_none()); + assert!(Target::parse("<").is_none()); } diff --git a/src/elements/timestamp.rs b/src/elements/timestamp.rs index b0a263f..15f1255 100644 --- a/src/elements/timestamp.rs +++ b/src/elements/timestamp.rs @@ -4,7 +4,6 @@ use nom::{ bytes::complete::{tag, take, take_till, take_while, take_while_m_n}, character::complete::{space0, space1}, combinator::{map, map_res, opt}, - error::ParseError, sequence::preceded, IResult, }; @@ -139,15 +138,15 @@ pub enum Timestamp<'a> { impl Timestamp<'_> { pub(crate) fn parse_active(input: &str) -> Option<(&str, Timestamp)> { - parse_active::<()>(input).ok() + parse_active(input).ok() } pub(crate) fn parse_inactive(input: &str) -> Option<(&str, Timestamp)> { - parse_inactive::<()>(input).ok() + parse_inactive(input).ok() } pub(crate) fn parse_diary(input: &str) -> Option<(&str, Timestamp)> { - parse_diary::<()>(input).ok() + parse_diary(input).ok() } pub fn into_owned(self) -> Timestamp<'static> { @@ -199,7 +198,7 @@ impl Timestamp<'_> { } } -pub fn parse_active<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Timestamp, E> { +pub fn parse_active(input: &str) -> IResult<&str, Timestamp, ()> { let (input, _) = tag("<")(input)?; let (input, start) = parse_datetime(input)?; @@ -252,7 +251,7 @@ pub fn parse_active<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, } } -pub fn parse_inactive<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Timestamp, E> { +pub fn parse_inactive(input: &str) -> IResult<&str, Timestamp, ()> { let (input, _) = tag("[")(input)?; let (input, start) = parse_datetime(input)?; @@ -305,7 +304,7 @@ pub fn parse_inactive<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&st } } -pub fn parse_diary<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Timestamp, E> { +pub fn parse_diary(input: &str) -> IResult<&str, Timestamp, ()> { let (input, _) = tag("<%%(")(input)?; let (input, value) = take_till(|c| c == ')' || c == '>' || c == '\n')(input)?; let (input, _) = tag(")>")(input)?; @@ -318,7 +317,7 @@ pub fn parse_diary<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, )) } -fn parse_time<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, (u8, u8), E> { +fn parse_time(input: &str) -> IResult<&str, (u8, u8), ()> { let (input, hour) = map_res(take_while_m_n(1, 2, |c: char| c.is_ascii_digit()), |num| { u8::from_str_radix(num, 10) })(input)?; @@ -327,7 +326,7 @@ fn parse_time<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, (u8, Ok((input, (hour, minute))) } -fn parse_datetime<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, Datetime, E> { +fn parse_datetime(input: &str) -> IResult<&str, Datetime, ()> { let parse_u8 = |num| u8::from_str_radix(num, 10); let (input, year) = map_res(take(4usize), |num| u16::from_str_radix(num, 10))(input)?; @@ -410,10 +409,8 @@ fn parse_datetime<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&str, D #[test] fn parse() { - use nom::error::VerboseError; - assert_eq!( - parse_inactive::>("[2003-09-16 Tue]"), + parse_inactive("[2003-09-16 Tue]"), Ok(( "", Timestamp::Inactive { @@ -431,7 +428,7 @@ fn parse() { )) ); assert_eq!( - parse_inactive::>("[2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39]"), + parse_inactive("[2003-09-16 Tue 09:39]--[2003-09-16 Tue 10:39]"), Ok(( "", Timestamp::InactiveRange { @@ -457,7 +454,7 @@ fn parse() { )) ); assert_eq!( - parse_active::>("<2003-09-16 Tue 09:39-10:39>"), + parse_active("<2003-09-16 Tue 09:39-10:39>"), Ok(( "", Timestamp::ActiveRange { diff --git a/src/elements/title.rs b/src/elements/title.rs index f2e358e..30c7bdf 100644 --- a/src/elements/title.rs +++ b/src/elements/title.rs @@ -8,7 +8,7 @@ use nom::{ bytes::complete::{tag, take_until, take_while}, character::complete::{anychar, space1}, combinator::{map, map_parser, opt, verify}, - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, multi::fold_many0, sequence::{delimited, preceded}, Err, IResult, @@ -54,7 +54,7 @@ impl Title<'_> { input: &'a str, config: &ParseConfig, ) -> Option<(&'a str, (Title<'a>, &'a str))> { - parse_title::<()>(input, config).ok() + parse_title(input, config).ok() } // TODO: fn is_quoted(&self) -> bool { } @@ -123,13 +123,7 @@ impl Default for Title<'_> { } #[inline] -fn parse_title<'a, E>( - input: &'a str, - config: &ParseConfig, -) -> IResult<&'a str, (Title<'a>, &'a str), E> -where - E: ParseError<&'a str>, -{ +fn parse_title<'a>(input: &'a str, config: &ParseConfig) -> IResult<&'a str, (Title<'a>, &'a str), ()> { let (input, level) = map(take_while(|c: char| c == '*'), |s: &str| s.len())(input)?; debug_assert!(level > 0); @@ -203,12 +197,10 @@ fn is_tag_line(input: &str) -> bool { } #[inline] -fn parse_properties_drawer<'a, E: ParseError<&'a str>>( - input: &'a str, -) -> IResult<&str, HashMap, Cow<'_, str>>, E> { +fn parse_properties_drawer(input: &str) -> IResult<&str, HashMap, Cow<'_, str>>, ()> { let (input, (drawer, content)) = parse_drawer_without_blank(input.trim_start())?; if drawer.name != "PROPERTIES" { - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Tag))); + return Err(Err::Error(make_error(input, ErrorKind::Tag))); } let (_, map) = fold_many0( parse_node_property, @@ -222,9 +214,7 @@ fn parse_properties_drawer<'a, E: ParseError<&'a str>>( } #[inline] -fn parse_node_property<'a, E: ParseError<&'a str>>( - input: &'a str, -) -> IResult<&str, (&str, &str), E> { +fn parse_node_property(input: &str) -> IResult<&str, (&str, &str), ()> { let (input, _) = blank_lines_count(input)?; let input = input.trim_start(); let (input, name) = map(delimited(tag(":"), take_until(":"), tag(":")), |s: &str| { @@ -236,15 +226,10 @@ fn parse_node_property<'a, E: ParseError<&'a str>>( #[test] fn parse_title_() { - use nom::error::VerboseError; - use crate::config::DEFAULT_CONFIG; assert_eq!( - parse_title::>( - "**** DONE [#A] COMMENT Title :tag:a2%:", - &DEFAULT_CONFIG - ), + parse_title("**** DONE [#A] COMMENT Title :tag:a2%:", &DEFAULT_CONFIG), Ok(( "", ( @@ -263,7 +248,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** ToDO [#A] COMMENT Title", &DEFAULT_CONFIG), + parse_title("**** ToDO [#A] COMMENT Title", &DEFAULT_CONFIG), Ok(( "", ( @@ -282,7 +267,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** T0DO [#A] COMMENT Title", &DEFAULT_CONFIG), + parse_title("**** T0DO [#A] COMMENT Title", &DEFAULT_CONFIG), Ok(( "", ( @@ -301,7 +286,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** DONE [#1] COMMENT Title", &DEFAULT_CONFIG), + parse_title("**** DONE [#1] COMMENT Title", &DEFAULT_CONFIG), Ok(( "", ( @@ -320,7 +305,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** DONE [#a] COMMENT Title", &DEFAULT_CONFIG), + parse_title("**** DONE [#a] COMMENT Title", &DEFAULT_CONFIG), Ok(( "", ( @@ -339,7 +324,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** Title :tag:a2%", &DEFAULT_CONFIG), + parse_title("**** Title :tag:a2%", &DEFAULT_CONFIG), Ok(( "", ( @@ -358,7 +343,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>("**** Title tag:a2%:", &DEFAULT_CONFIG), + parse_title("**** Title tag:a2%:", &DEFAULT_CONFIG), Ok(( "", ( @@ -378,7 +363,7 @@ fn parse_title_() { ); assert_eq!( - parse_title::>( + parse_title( "**** DONE Title", &ParseConfig { todo_keywords: (vec![], vec![]), @@ -403,7 +388,7 @@ fn parse_title_() { )) ); assert_eq!( - parse_title::>( + parse_title( "**** TASK [#A] Title", &ParseConfig { todo_keywords: (vec!["TASK".to_string()], vec![]), @@ -431,12 +416,8 @@ fn parse_title_() { #[test] fn parse_properties_drawer_() { - use nom::error::VerboseError; - assert_eq!( - parse_properties_drawer::>( - " :PROPERTIES:\n :CUSTOM_ID: id\n :END:" - ), + parse_properties_drawer(" :PROPERTIES:\n :CUSTOM_ID: id\n :END:"), Ok(( "", vec![("CUSTOM_ID".into(), "id".into())] diff --git a/src/parse/combinators.rs b/src/parse/combinators.rs index 74b48e1..746a097 100644 --- a/src/parse/combinators.rs +++ b/src/parse/combinators.rs @@ -4,15 +4,12 @@ use memchr::memchr; use nom::{ bytes::complete::take_while1, combinator::verify, - error::{ErrorKind, ParseError}, + error::{make_error, ErrorKind}, Err, IResult, }; // read until the first line_ending, if line_ending is not present, return the input directly -pub fn line<'a, E>(input: &'a str) -> IResult<&'a str, &'a str, E> -where - E: ParseError<&'a str>, -{ +pub fn line(input: &str) -> IResult<&str, &str, ()> { if let Some(i) = memchr(b'\n', input.as_bytes()) { if i > 0 && input.as_bytes()[i - 1] == b'\r' { Ok((&input[i + 1..], &input[0..i - 1])) @@ -24,10 +21,9 @@ where } } -pub fn lines_till<'a, F, E>(predicate: F) -> impl Fn(&'a str) -> IResult<&str, &str, E> +pub fn lines_till(predicate: F) -> impl Fn(&str) -> IResult<&str, &str, ()> where F: Fn(&str) -> bool, - E: ParseError<&'a str>, { move |i| { let mut input = i; @@ -35,7 +31,7 @@ where loop { // TODO: better error kind if input.is_empty() { - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many0))); + return Err(Err::Error(make_error(input, ErrorKind::Many0))); } let (input_, line_) = line(input)?; @@ -52,10 +48,9 @@ where } } -pub fn lines_while<'a, F, E>(predicate: F) -> impl Fn(&'a str) -> IResult<&str, &str, E> +pub fn lines_while(predicate: F) -> impl Fn(&str) -> IResult<&str, &str, ()> where F: Fn(&str) -> bool, - E: ParseError<&'a str>, { move |i| { let mut input = i; @@ -82,44 +77,29 @@ where #[test] fn test_lines_while() { + assert_eq!(lines_while(|line| line == "foo")("foo"), Ok(("", "foo"))); + assert_eq!(lines_while(|line| line == "foo")("bar"), Ok(("bar", ""))); assert_eq!( - lines_while::<_, ()>(|line| line == "foo")("foo"), - Ok(("", "foo")) - ); - assert_eq!( - lines_while::<_, ()>(|line| line == "foo")("bar"), - Ok(("bar", "")) - ); - assert_eq!( - lines_while::<_, ()>(|line| line == "foo")("foo\n\n"), + lines_while(|line| line == "foo")("foo\n\n"), Ok(("\n", "foo\n")) ); assert_eq!( - lines_while::<_, ()>(|line| line.trim().is_empty())("\n\n\n"), + lines_while(|line| line.trim().is_empty())("\n\n\n"), Ok(("", "\n\n\n")) ); } -pub fn eol<'a, E>(input: &'a str) -> IResult<&str, &str, E> -where - E: ParseError<&'a str>, -{ +pub fn eol(input: &str) -> IResult<&str, &str, ()> { verify(line, |s: &str| { s.as_bytes().iter().all(u8::is_ascii_whitespace) })(input) } -pub fn one_word<'a, E>(input: &'a str) -> IResult<&str, &str, E> -where - E: ParseError<&'a str>, -{ +pub fn one_word(input: &str) -> IResult<&str, &str, ()> { take_while1(|c: char| !c.is_ascii_whitespace())(input) } -pub fn blank_lines_count<'a, E>(input: &'a str) -> IResult<&str, usize, E> -where - E: ParseError<&'a str>, -{ +pub fn blank_lines_count(input: &str) -> IResult<&str, usize, ()> { let mut count = 0; let mut input = input; @@ -144,16 +124,13 @@ where #[test] fn test_blank_lines_count() { - assert_eq!(blank_lines_count::<()>("foo"), Ok(("foo", 0))); - assert_eq!(blank_lines_count::<()>(" foo"), Ok((" foo", 0))); - assert_eq!(blank_lines_count::<()>(" \t\nfoo\n"), Ok(("foo\n", 1))); + assert_eq!(blank_lines_count("foo"), Ok(("foo", 0))); + assert_eq!(blank_lines_count(" foo"), Ok((" foo", 0))); + assert_eq!(blank_lines_count(" \t\nfoo\n"), Ok(("foo\n", 1))); + assert_eq!(blank_lines_count("\n \r\n\nfoo\n"), Ok(("foo\n", 3))); assert_eq!( - blank_lines_count::<()>("\n \r\n\nfoo\n"), - Ok(("foo\n", 3)) - ); - assert_eq!( - blank_lines_count::<()>("\r\n \n \r\n foo\n"), + blank_lines_count("\r\n \n \r\n foo\n"), Ok((" foo\n", 3)) ); - assert_eq!(blank_lines_count::<()>("\r\n \n \r\n \n"), Ok(("", 4))); + assert_eq!(blank_lines_count("\r\n \n \r\n \n"), Ok(("", 4))); } diff --git a/src/parsers.rs b/src/parsers.rs index aed17aa..d277057 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -560,8 +560,7 @@ pub fn parse_org_table<'a, T: ElementArena<'a>>( parent: NodeId, ) -> &'a str { let (tail, contents) = - lines_while::<_, ()>(|line| line.trim_start().starts_with('|'))(contents) - .unwrap_or((contents, "")); + lines_while(|line| line.trim_start().starts_with('|'))(contents).unwrap_or((contents, "")); let (tail, post_blank) = blank_lines_count(tail); let mut iter = contents.trim_end().lines().peekable(); @@ -633,12 +632,12 @@ pub fn parse_org_table<'a, T: ElementArena<'a>>( } pub fn blank_lines_count(input: &str) -> (&str, usize) { - crate::parse::combinators::blank_lines_count::<()>(input).unwrap_or((input, 0)) + crate::parse::combinators::blank_lines_count(input).unwrap_or((input, 0)) } pub fn parse_headline(input: &str) -> Option<(&str, (&str, usize))> { let (input_, level) = parse_headline_level(input)?; - let (input_, content) = lines_while::<_, ()>(move |line| { + let (input_, content) = lines_while(move |line| { parse_headline_level(line) .map(|(_, l)| l > level) .unwrap_or(true)