Move the affiliated keywords parser inside the specific element parsers.

We need access to the affiliated keywords to do things like set the name of the element, and only half the element parsers are allowed to have affiliated keywords, so it makes sense to move it inside the specific parsers.
This commit is contained in:
Tom Alexander
2023-10-04 20:01:09 -04:00
parent a26640355c
commit d8102b7bc2
32 changed files with 324 additions and 59 deletions

View File

@@ -3,9 +3,12 @@ use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
use nom::character::complete::line_ending;
use nom::combinator::eof;
use nom::multi::many0;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use crate::context::parser_with_context;
use crate::context::RefContext;
use crate::error::Res;
use crate::parser::util::get_consumed;
@@ -14,9 +17,11 @@ use crate::types::DiarySexp;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn diary_sexp<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, DiarySexp<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, _clock) = tag("%%(")(input)?;
let (remaining, _contents) = is_not("\r\n")(remaining)?;
@@ -27,6 +32,7 @@ pub(crate) fn diary_sexp<'b, 'g, 'r, 's>(
remaining,
DiarySexp {
source: source.into(),
name: None, // TODO
},
))
}

View File

@@ -7,9 +7,11 @@ use nom::character::complete::space0;
use nom::combinator::eof;
use nom::combinator::not;
use nom::combinator::recognize;
use nom::multi::many0;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use crate::context::parser_with_context;
use crate::context::ContextElement;
@@ -41,6 +43,8 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, (_open_colon, drawer_name, _close_colon, _new_line)) = tuple((
@@ -90,7 +94,8 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>(
remaining,
Drawer {
source: source.into(),
name: drawer_name.into(),
name: None, // TODO
drawer_name: drawer_name.into(),
children,
},
))

View File

@@ -17,6 +17,7 @@ use nom::multi::many_till;
use nom::sequence::preceded;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use crate::context::parser_with_context;
use crate::context::ContextElement;
@@ -47,6 +48,9 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, (_, name, parameters, _, _)) = tuple((
@@ -97,7 +101,8 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>(
remaining,
DynamicBlock {
source: source.into(),
name: name.into(),
name: None, // TODO
block_name: name.into(),
parameters: parameters.map(|val| val.into()),
children,
},

View File

@@ -1,8 +1,5 @@
use nom::branch::alt;
use nom::combinator::map;
use nom::combinator::not;
use nom::multi::many0;
use nom::sequence::tuple;
use super::clock::clock;
use super::comment::comment;
@@ -79,8 +76,6 @@ fn _element<'b, 'g, 'r, 's>(
let paragraph_matcher = parser_with_context!(paragraph)(context);
let latex_environment_matcher = parser_with_context!(latex_environment)(context);
// TODO: Affiliated keywords cannot be on comments, clocks, headings, inlinetasks, items, node properties, planning, property drawers, sections, and table rows
let (remaining, mut affiliated_keywords) = many0(affiliated_keyword_matcher)(input)?;
let (remaining, mut element) = match alt((
map(plain_list_matcher, Element::PlainList),
greater_block_matcher,
@@ -100,28 +95,20 @@ fn _element<'b, 'g, 'r, 's>(
map(horizontal_rule_matcher, Element::HorizontalRule),
map(latex_environment_matcher, Element::LatexEnvironment),
map(babel_keyword_matcher, Element::BabelCall),
map(
map(
tuple((not(affiliated_keyword_matcher), keyword_matcher)),
|(_, kw)| kw,
),
Element::Keyword,
),
))(remaining)
map(keyword_matcher, Element::Keyword),
))(input)
{
the_ok @ Ok(_) => the_ok,
Err(_) => {
if can_be_paragraph {
match map(paragraph_matcher, Element::Paragraph)(remaining) {
match map(paragraph_matcher, Element::Paragraph)(input) {
the_ok @ Ok(_) => the_ok,
Err(_) => {
// TODO: Because this function expects a single element, if there are multiple affiliated keywords before an element that cannot have affiliated keywords, we end up re-parsing the affiliated keywords many times.
affiliated_keywords.clear();
map(affiliated_keyword_matcher, Element::Keyword)(input)
}
}
} else {
affiliated_keywords.clear();
map(affiliated_keyword_matcher, Element::Keyword)(input)
}
}
@@ -149,6 +136,7 @@ fn _detect_element<'b, 'g, 'r, 's>(
input: OrgSource<'s>,
can_be_paragraph: bool,
) -> Res<OrgSource<'s>, ()> {
// TODO: What about affiliated keywords in the detect_* functions?
if alt((
parser_with_context!(detect_plain_list)(context),
detect_footnote_definition,

View File

@@ -10,6 +10,7 @@ use nom::multi::many0;
use nom::sequence::preceded;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::only_space1;
use super::util::org_line_ending;
@@ -26,6 +27,8 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, FixedWidthArea<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(context);
let (remaining, _first_line) = fixed_width_area_line_matcher(input)?;
@@ -37,6 +40,7 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>(
remaining,
FixedWidthArea {
source: source.into(),
name: None, // TODO
},
))
}

View File

@@ -11,6 +11,7 @@ use nom::multi::many1;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::include_input;
use super::util::WORD_CONSTITUENT_CHARACTERS;
@@ -41,6 +42,8 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>(
"Cannot nest objects of the same element".into(),
))));
}
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
// Cannot be indented.
let (remaining, (_, lbl, _, _, _)) = tuple((
@@ -85,6 +88,7 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>(
remaining,
FootnoteDefinition {
source: source.into(),
name: None, // TODO
label: lbl.into(),
children: children.into_iter().map(|(_, item)| item).collect(),
},

View File

@@ -17,6 +17,7 @@ use nom::multi::many_till;
use nom::sequence::preceded;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::in_section;
use crate::context::parser_with_context;
@@ -45,6 +46,8 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Element<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, (_begin, name)) = tuple((
@@ -75,7 +78,11 @@ fn center_block<'b, 'g, 'r, 's>(
greater_block_body(context, input, original_input, "center", "center block")?;
Ok((
remaining,
Element::CenterBlock(CenterBlock { source, children }),
Element::CenterBlock(CenterBlock {
source,
name: None, // TODO
children,
}),
))
}
@@ -89,7 +96,11 @@ fn quote_block<'b, 'g, 'r, 's>(
greater_block_body(context, input, original_input, "quote", "quote block")?;
Ok((
remaining,
Element::QuoteBlock(QuoteBlock { source, children }),
Element::QuoteBlock(QuoteBlock {
source,
name: None, // TODO
children,
}),
))
}
@@ -122,8 +133,9 @@ fn _special_block<'c, 'b, 'g, 'r, 's>(
remaining,
Element::SpecialBlock(SpecialBlock {
source,
name: None, // TODO
children,
name,
block_type: name,
parameters: parameters.map(|(_, parameters)| Into::<&str>::into(parameters)),
}),
))

View File

@@ -5,10 +5,13 @@ use nom::character::complete::space0;
use nom::combinator::eof;
use nom::combinator::recognize;
use nom::combinator::verify;
use nom::multi::many0;
use nom::multi::many1_count;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use crate::context::parser_with_context;
use crate::context::RefContext;
use crate::error::Res;
use crate::parser::util::start_of_line;
@@ -16,9 +19,11 @@ use crate::types::HorizontalRule;
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, HorizontalRule<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, rule) = recognize(tuple((
space0,
@@ -30,6 +35,7 @@ pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>(
remaining,
HorizontalRule {
source: rule.into(),
name: None, // TODO
},
))
}

View File

@@ -13,11 +13,13 @@ use nom::combinator::not;
use nom::combinator::peek;
use nom::combinator::recognize;
use nom::combinator::verify;
use nom::multi::many0;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::org_source::BracketDepth;
use super::org_source::OrgSource;
use crate::context::parser_with_context;
use crate::context::Matcher;
use crate::context::RefContext;
use crate::error::CustomError;
@@ -61,6 +63,7 @@ fn _filtered_keyword<'s, F: Matcher>(
remaining,
Keyword {
source: consumed_input.into(),
name: None, // TODO
key: parsed_key.into(),
value: "".into(),
},
@@ -78,6 +81,7 @@ fn _filtered_keyword<'s, F: Matcher>(
remaining,
Keyword {
source: consumed_input.into(),
name: None, // TODO
key: parsed_key.into(),
value: parsed_value.into(),
},
@@ -86,9 +90,11 @@ fn _filtered_keyword<'s, F: Matcher>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn keyword<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Keyword<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
filtered_keyword(regular_keyword_key)(input)
}
@@ -102,14 +108,17 @@ pub(crate) fn affiliated_keyword<'b, 'g, 'r, 's>(
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
pub(crate) fn babel_call_keyword<'b, 'g, 'r, 's>(
_context: RefContext<'b, 'g, 'r, 's>,
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, BabelCall<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
let (remaining, kw) = filtered_keyword(babel_call_key)(input)?;
Ok((
remaining,
BabelCall {
source: kw.source,
name: None, // TODO
key: kw.key,
value: kw.value,
},

View File

@@ -8,9 +8,11 @@ use nom::character::complete::space0;
use nom::combinator::eof;
use nom::combinator::peek;
use nom::combinator::recognize;
use nom::multi::many0;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::get_consumed;
use crate::context::parser_with_context;
@@ -29,6 +31,8 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, LatexEnvironment<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
let (remaining, _leading_whitespace) = space0(input)?;
let (remaining, (_opening, name, _open_close_brace, _ws, _line_ending)) = tuple((
@@ -54,6 +58,7 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>(
remaining,
LatexEnvironment {
source: source.into(),
name: None, // TODO
},
))
}

View File

@@ -2,11 +2,13 @@ use nom::branch::alt;
use nom::combinator::eof;
use nom::combinator::recognize;
use nom::combinator::verify;
use nom::multi::many0;
use nom::multi::many1;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::element_parser::detect_element;
use super::keyword::affiliated_keyword;
use super::org_source::OrgSource;
use super::util::blank_line;
use super::util::get_consumed;
@@ -26,6 +28,9 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Paragraph<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Gamma,
exit_matcher: &paragraph_end,

View File

@@ -19,6 +19,7 @@ use nom::multi::many_till;
use nom::sequence::tuple;
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;
@@ -78,6 +79,9 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, PlainList<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
let contexts = [
ContextElement::Context("plain list"),
ContextElement::ConsumeTrailingWhitespace(true),
@@ -150,6 +154,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>(
remaining,
PlainList {
source: source.into(),
name: None, // TODO
list_type: first_item_list_type.expect("Plain lists require at least one element."),
children: children.into_iter().map(|(_start, item)| item).collect(),
},

View File

@@ -120,7 +120,7 @@ fn node_property<'b, 'g, 'r, 's>(
remaining,
NodeProperty {
source: source.into(),
name: Into::<&str>::into(name),
property_name: Into::<&str>::into(name),
value: None,
},
))
@@ -133,7 +133,7 @@ fn node_property<'b, 'g, 'r, 's>(
remaining,
NodeProperty {
source: source.into(),
name: Into::<&str>::into(name),
property_name: Into::<&str>::into(name),
value: Some(value.into()),
},
))

View File

@@ -13,6 +13,7 @@ use nom::multi::many1;
use nom::multi::many_till;
use nom::sequence::tuple;
use super::keyword::affiliated_keyword;
use super::keyword::table_formula_keyword;
use super::object_parser::table_cell_set_object;
use super::org_source::OrgSource;
@@ -38,6 +39,8 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, Table<'s>> {
let (input, affiliated_keywords) =
many0(parser_with_context!(affiliated_keyword)(context))(input)?;
start_of_line(input)?;
peek(tuple((space0, tag("|"))))(input)?;
@@ -68,6 +71,7 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>(
remaining,
Table {
source: source.into(),
name: None, // TODO
formulas,
children,
},