Merge branch 'object_parser_perf'
rustfmt Build rustfmt has succeeded Details
rust-foreign-document-test Build rust-foreign-document-test has failed Details
rust-build Build rust-build has succeeded Details
rust-test Build rust-test has succeeded Details

This commit is contained in:
Tom Alexander 2023-10-16 15:04:04 -04:00
commit 9f1671658d
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
8 changed files with 226 additions and 209 deletions

View File

@ -1,15 +1,12 @@
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::combinator::recognize;
use nom::multi::many0;
use nom::sequence::tuple;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
use crate::context::parser_with_context;
use crate::context::RefContext;
use crate::error::Res;
use crate::parser::util::get_consumed;
@ -50,12 +47,19 @@ where
))
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn detect_diary_sexp<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(_context, _affiliated_keywords))
)]
pub(crate) fn detect_diary_sexp<'b, 'g, 'r, 's, AK>(
_affiliated_keywords: AK,
remaining: OrgSource<'s>,
_context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
let (input, _) = many0(parser_with_context!(affiliated_keyword)(context))(input)?;
tuple((start_of_line, tag("%%(")))(input)?;
) -> Res<OrgSource<'s>, ()>
where
AK: IntoIterator<Item = Keyword<'s>>,
{
tuple((start_of_line, tag("%%(")))(remaining)?;
Ok((input, ()))
}

View File

@ -1,4 +1,4 @@
use nom::branch::alt;
use nom::multi::many0;
use super::babel_call::babel_call;
@ -273,23 +273,60 @@ fn _detect_element<'b, 'g, 'r, 's>(
input: OrgSource<'s>,
can_be_paragraph: bool,
) -> Res<OrgSource<'s>, ()> {
// TODO: unify parsing of affiliated keywords like we did for the element parser.
if alt((
parser_with_context!(detect_plain_list)(context),
parser_with_context!(detect_footnote_definition)(context),
parser_with_context!(detect_diary_sexp)(context),
detect_comment,
parser_with_context!(detect_fixed_width_area)(context),
parser_with_context!(detect_table)(context),
))(input)
.is_ok()
{
let (post_affiliated_keywords_input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
let mut affiliated_keywords = affiliated_keywords.into_iter();
ak_element!(
detect_plain_list,
&mut affiliated_keywords,
post_affiliated_keywords_input,
context,
input
);
ak_element!(
detect_footnote_definition,
&mut affiliated_keywords,
post_affiliated_keywords_input,
context,
input
);
ak_element!(
detect_diary_sexp,
&mut affiliated_keywords,
post_affiliated_keywords_input,
context,
input
);
if let Ok((_, _)) = detect_comment(input) {
return Ok((input, ()));
}
ak_element!(
detect_fixed_width_area,
&mut affiliated_keywords,
post_affiliated_keywords_input,
context,
input
);
ak_element!(
detect_table,
&mut affiliated_keywords,
post_affiliated_keywords_input,
context,
input
);
if _element(context, input, can_be_paragraph).is_ok() {
return Ok((input, ()));
}
return Err(nom::Err::Error(CustomError::MyError(MyError(
Err(nom::Err::Error(CustomError::MyError(MyError(
"No element detected.".into(),
))));
))))
}

View File

@ -10,7 +10,6 @@ use nom::sequence::preceded;
use nom::sequence::tuple;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
use super::util::org_line_ending;
@ -89,17 +88,24 @@ fn fixed_width_area_line<'b, 'g, 'r, 's>(
Ok((remaining, value))
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn detect_fixed_width_area<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(_context, _affiliated_keywords))
)]
pub(crate) fn detect_fixed_width_area<'b, 'g, 'r, 's, AK>(
_affiliated_keywords: AK,
remaining: OrgSource<'s>,
_context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
let (input, _) = many0(parser_with_context!(affiliated_keyword)(context))(input)?;
) -> Res<OrgSource<'s>, ()>
where
AK: IntoIterator<Item = Keyword<'s>>,
{
tuple((
start_of_line,
space0,
tag(":"),
alt((tag(" "), org_line_ending)),
))(input)?;
))(remaining)?;
Ok((input, ()))
}

View File

@ -12,7 +12,6 @@ use nom::multi::many_till;
use nom::sequence::tuple;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::include_input;
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
@ -125,7 +124,7 @@ fn footnote_definition_end<'b, 'g, 'r, 's>(
let (remaining, source) = alt((
recognize(tuple((
parser_with_context!(maybe_consume_trailing_whitespace)(context),
parser_with_context!(detect_footnote_definition)(context),
|i| detect_footnote_definition(std::iter::empty(), i, context, i),
))),
recognize(tuple((
start_of_line,
@ -138,13 +137,20 @@ fn footnote_definition_end<'b, 'g, 'r, 's>(
Ok((remaining, source))
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn detect_footnote_definition<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(_context, _affiliated_keywords))
)]
pub(crate) fn detect_footnote_definition<'b, 'g, 'r, 's, AK>(
_affiliated_keywords: AK,
remaining: OrgSource<'s>,
_context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
let (input, _) = many0(parser_with_context!(affiliated_keyword)(context))(input)?;
tuple((start_of_line, tag_no_case("[fn:"), label, tag("]")))(input)?;
) -> Res<OrgSource<'s>, ()>
where
AK: IntoIterator<Item = Keyword<'s>>,
{
tuple((start_of_line, tag_no_case("[fn:"), label, tag("]")))(remaining)?;
Ok((input, ()))
}

View File

@ -1,6 +1,6 @@
/// Parse an element that has affiliated keywords.
macro_rules! ak_element {
($parser:ident, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr, $wrapper: expr) => {
($parser:expr, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr, $wrapper: expr) => {
if let Ok((remaining, ele)) = $parser(
$affiliated_keywords,
$post_affiliated_keywords_input,
@ -10,7 +10,7 @@ macro_rules! ak_element {
return Ok((remaining, $wrapper(ele)));
}
};
($parser:ident, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr) => {
($parser:expr, $affiliated_keywords:expr, $post_affiliated_keywords_input: expr, $context: expr, $input: expr) => {
if let Ok((remaining, ele)) = $parser(
$affiliated_keywords,
$post_affiliated_keywords_input,
@ -25,12 +25,12 @@ macro_rules! ak_element {
pub(crate) use ak_element;
macro_rules! element {
($parser:ident, $context: expr, $input: expr, $wrapper: expr) => {
($parser:expr, $context: expr, $input: expr, $wrapper: expr) => {
if let Ok((remaining, ele)) = $parser($context, $input) {
return Ok((remaining, $wrapper(ele)));
}
};
($parser:ident, $context: expr, $input: expr) => {
($parser:expr, $context: expr, $input: expr) => {
if let Ok((remaining, ele)) = $parser($context, $input) {
return Ok((remaining, ele));
}

View File

@ -1,11 +1,7 @@
use nom::branch::alt;
use nom::combinator::map;
use super::org_source::OrgSource;
use super::plain_text::plain_text;
use super::regular_link::regular_link;
use super::subscript_and_superscript::detect_subscript_or_superscript;
use crate::context::parser_with_context;
use crate::context::RefContext;
use crate::error::CustomError;
use crate::error::MyError;
@ -19,6 +15,7 @@ use crate::parser::inline_babel_call::inline_babel_call;
use crate::parser::inline_source_block::inline_source_block;
use crate::parser::latex_fragment::latex_fragment;
use crate::parser::line_break::line_break;
use crate::parser::macros::element;
use crate::parser::org_macro::org_macro;
use crate::parser::plain_link::plain_link;
use crate::parser::radio_link::radio_link;
@ -39,14 +36,14 @@ pub(crate) fn standard_set_object<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
parser_with_context!(standard_set_object_sans_plain_text)(context),
map(
parser_with_context!(plain_text(detect_standard_set_object_sans_plain_text))(context),
Object::PlainText,
),
))(input)?;
Ok((remaining, object))
element!(standard_set_object_sans_plain_text, context, input);
element!(
plain_text(detect_standard_set_object_sans_plain_text),
context,
input,
Object::PlainText
);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -57,14 +54,14 @@ pub(crate) fn minimal_set_object<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
parser_with_context!(minimal_set_object_sans_plain_text)(context),
map(
parser_with_context!(plain_text(detect_minimal_set_object_sans_plain_text))(context),
Object::PlainText,
),
))(input)?;
Ok((remaining, object))
element!(minimal_set_object_sans_plain_text, context, input);
element!(
plain_text(detect_minimal_set_object_sans_plain_text),
context,
input,
Object::PlainText
);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -75,56 +72,38 @@ fn standard_set_object_sans_plain_text<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
map(parser_with_context!(timestamp)(context), Object::Timestamp),
map(parser_with_context!(subscript)(context), Object::Subscript),
map(
parser_with_context!(superscript)(context),
Object::Superscript,
),
map(
parser_with_context!(statistics_cookie)(context),
Object::StatisticsCookie,
),
map(parser_with_context!(target)(context), Object::Target),
map(parser_with_context!(line_break)(context), Object::LineBreak),
map(
parser_with_context!(inline_source_block)(context),
Object::InlineSourceBlock,
),
map(
parser_with_context!(inline_babel_call)(context),
Object::InlineBabelCall,
),
map(parser_with_context!(citation)(context), Object::Citation),
map(
parser_with_context!(footnote_reference)(context),
Object::FootnoteReference,
),
map(
parser_with_context!(export_snippet)(context),
Object::ExportSnippet,
),
map(parser_with_context!(entity)(context), Object::Entity),
map(
parser_with_context!(latex_fragment)(context),
Object::LatexFragment,
),
map(parser_with_context!(radio_link)(context), Object::RadioLink),
map(
parser_with_context!(radio_target)(context),
Object::RadioTarget,
),
parser_with_context!(text_markup)(context),
map(
parser_with_context!(regular_link)(context),
Object::RegularLink,
),
map(parser_with_context!(plain_link)(context), Object::PlainLink),
map(parser_with_context!(angle_link)(context), Object::AngleLink),
map(parser_with_context!(org_macro)(context), Object::OrgMacro),
))(input)?;
Ok((remaining, object))
element!(timestamp, context, input, Object::Timestamp);
element!(subscript, context, input, Object::Subscript);
element!(superscript, context, input, Object::Superscript);
element!(statistics_cookie, context, input, Object::StatisticsCookie);
element!(target, context, input, Object::Target);
element!(line_break, context, input, Object::LineBreak);
element!(
inline_source_block,
context,
input,
Object::InlineSourceBlock
);
element!(inline_babel_call, context, input, Object::InlineBabelCall);
element!(citation, context, input, Object::Citation);
element!(
footnote_reference,
context,
input,
Object::FootnoteReference
);
element!(export_snippet, context, input, Object::ExportSnippet);
element!(entity, context, input, Object::Entity);
element!(latex_fragment, context, input, Object::LatexFragment);
element!(radio_link, context, input, Object::RadioLink);
element!(radio_target, context, input, Object::RadioTarget);
element!(text_markup, context, input);
element!(regular_link, context, input, Object::RegularLink);
element!(plain_link, context, input, Object::PlainLink);
element!(angle_link, context, input, Object::AngleLink);
element!(org_macro, context, input, Object::OrgMacro);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -135,20 +114,12 @@ fn minimal_set_object_sans_plain_text<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
map(parser_with_context!(subscript)(context), Object::Subscript),
map(
parser_with_context!(superscript)(context),
Object::Superscript,
),
map(parser_with_context!(entity)(context), Object::Entity),
map(
parser_with_context!(latex_fragment)(context),
Object::LatexFragment,
),
parser_with_context!(text_markup)(context),
))(input)?;
Ok((remaining, object))
element!(subscript, context, input, Object::Subscript);
element!(superscript, context, input, Object::Superscript);
element!(entity, context, input, Object::Entity);
element!(latex_fragment, context, input, Object::LatexFragment);
element!(text_markup, context, input);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -200,16 +171,18 @@ pub(crate) fn regular_link_description_set_object<'b, 'g, 'r, 's>(
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
// TODO: It can also contain another link, but only when it is a plain or angle link. It can contain square brackets, but not ]]
let (remaining, object) = alt((
parser_with_context!(regular_link_description_set_object_sans_plain_text)(context),
map(
parser_with_context!(plain_text(
detect_regular_link_description_set_object_sans_plain_text
))(context),
Object::PlainText,
),
))(input)?;
Ok((remaining, object))
element!(
regular_link_description_set_object_sans_plain_text,
context,
input
);
element!(
plain_text(detect_regular_link_description_set_object_sans_plain_text),
context,
input,
Object::PlainText
);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -221,27 +194,18 @@ fn regular_link_description_set_object_sans_plain_text<'b, 'g, 'r, 's>(
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
// TODO: It can also contain another link, but only when it is a plain or angle link. It can contain square brackets, but not ]]
let (remaining, object) = alt((
map(
parser_with_context!(export_snippet)(context),
Object::ExportSnippet,
),
map(
parser_with_context!(statistics_cookie)(context),
Object::StatisticsCookie,
),
map(
parser_with_context!(inline_source_block)(context),
Object::InlineSourceBlock,
),
map(
parser_with_context!(inline_babel_call)(context),
Object::InlineBabelCall,
),
map(parser_with_context!(org_macro)(context), Object::OrgMacro),
parser_with_context!(minimal_set_object_sans_plain_text)(context),
))(input)?;
Ok((remaining, object))
element!(export_snippet, context, input, Object::ExportSnippet);
element!(statistics_cookie, context, input, Object::StatisticsCookie);
element!(
inline_source_block,
context,
input,
Object::InlineSourceBlock
);
element!(inline_babel_call, context, input, Object::InlineBabelCall);
element!(org_macro, context, input, Object::OrgMacro);
element!(minimal_set_object_sans_plain_text, context, input);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -272,14 +236,14 @@ pub(crate) fn table_cell_set_object<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
parser_with_context!(table_cell_set_object_sans_plain_text)(context),
map(
parser_with_context!(plain_text(detect_table_cell_set_object_sans_plain_text))(context),
Object::PlainText,
),
))(input)?;
Ok((remaining, object))
element!(table_cell_set_object_sans_plain_text, context, input);
element!(
plain_text(detect_table_cell_set_object_sans_plain_text),
context,
input,
Object::PlainText
);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(
@ -290,33 +254,24 @@ fn table_cell_set_object_sans_plain_text<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Object<'s>> {
let (remaining, object) = alt((
map(parser_with_context!(citation)(context), Object::Citation),
map(
parser_with_context!(export_snippet)(context),
Object::ExportSnippet,
),
map(
parser_with_context!(footnote_reference)(context),
Object::FootnoteReference,
),
map(parser_with_context!(radio_link)(context), Object::RadioLink),
map(
parser_with_context!(regular_link)(context),
Object::RegularLink,
),
map(parser_with_context!(plain_link)(context), Object::PlainLink),
map(parser_with_context!(angle_link)(context), Object::AngleLink),
map(parser_with_context!(org_macro)(context), Object::OrgMacro),
map(
parser_with_context!(radio_target)(context),
Object::RadioTarget,
),
map(parser_with_context!(target)(context), Object::Target),
map(parser_with_context!(timestamp)(context), Object::Timestamp),
parser_with_context!(minimal_set_object_sans_plain_text)(context),
))(input)?;
Ok((remaining, object))
element!(citation, context, input, Object::Citation);
element!(export_snippet, context, input, Object::ExportSnippet);
element!(
footnote_reference,
context,
input,
Object::FootnoteReference
);
element!(radio_link, context, input, Object::RadioLink);
element!(regular_link, context, input, Object::RegularLink);
element!(plain_link, context, input, Object::PlainLink);
element!(angle_link, context, input, Object::AngleLink);
element!(org_macro, context, input, Object::OrgMacro);
element!(radio_target, context, input, Object::RadioTarget);
element!(target, context, input, Object::Target);
element!(timestamp, context, input, Object::Timestamp);
element!(minimal_set_object_sans_plain_text, context, input);
Err(nom::Err::Error(CustomError::MyError(MyError("No object."))))
}
#[cfg_attr(

View File

@ -20,7 +20,6 @@ use nom::sequence::tuple;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::element_parser::element;
use super::keyword::affiliated_keyword;
use super::object_parser::standard_set_object;
use super::org_source::OrgSource;
use super::util::include_input;
@ -53,13 +52,17 @@ use crate::types::PlainListType;
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(context))
tracing::instrument(ret, level = "debug", skip(context, _affiliated_keywords))
)]
pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>(
pub(crate) fn detect_plain_list<'b, 'g, 'r, 's, AK>(
_affiliated_keywords: AK,
remaining: OrgSource<'s>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
let (input, _) = many0(parser_with_context!(affiliated_keyword)(context))(input)?;
) -> Res<OrgSource<'s>, ()>
where
AK: IntoIterator<Item = Keyword<'s>>,
{
if verify(
tuple((
start_of_line,
@ -70,7 +73,7 @@ pub(crate) fn detect_plain_list<'b, 'g, 'r, 's>(
|(_start, (indent_level, _), (_bullet_type, bull), _after_whitespace)| {
!Into::<&str>::into(bull).starts_with("*") || *indent_level > 0
},
)(input)
)(remaining)
.is_ok()
{
return Ok((input, ()));
@ -730,7 +733,7 @@ dolar"#,
let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let result = detect_plain_list(&initial_context, input);
let result = detect_plain_list(std::iter::empty(), input, &initial_context, input);
assert!(result.is_ok());
}
@ -740,7 +743,7 @@ dolar"#,
let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let result = detect_plain_list(&initial_context, input);
let result = detect_plain_list(std::iter::empty(), input, &initial_context, input);
assert!(result.is_ok());
}
@ -750,7 +753,7 @@ dolar"#,
let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let result = detect_plain_list(&initial_context, input);
let result = detect_plain_list(std::iter::empty(), input, &initial_context, input);
// Since there is no whitespace after the '+' this is a paragraph, not a plain list.
assert!(result.is_err());
}
@ -761,7 +764,7 @@ dolar"#,
let global_settings = GlobalSettings::default();
let initial_context = ContextElement::document_context();
let initial_context = Context::new(&global_settings, List::new(&initial_context));
let result = detect_plain_list(&initial_context, input);
let result = detect_plain_list(std::iter::empty(), input, &initial_context, input);
assert!(result.is_ok());
}
}

View File

@ -14,7 +14,6 @@ use nom::multi::many_till;
use nom::sequence::tuple;
use super::affiliated_keyword::parse_affiliated_keywords;
use super::keyword::affiliated_keyword;
use super::keyword::table_formula_keyword;
use super::object_parser::table_cell_set_object;
use super::org_source::OrgSource;
@ -92,13 +91,20 @@ where
))
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn detect_table<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(_context, _affiliated_keywords))
)]
pub(crate) fn detect_table<'b, 'g, 'r, 's, AK>(
_affiliated_keywords: AK,
remaining: OrgSource<'s>,
_context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, ()> {
let (input, _) = many0(parser_with_context!(affiliated_keyword)(context))(input)?;
tuple((start_of_line, space0, tag("|")))(input)?;
) -> Res<OrgSource<'s>, ()>
where
AK: IntoIterator<Item = Keyword<'s>>,
{
tuple((start_of_line, space0, tag("|")))(remaining)?;
Ok((input, ()))
}