Implement the second parsing pass.
This commit is contained in:
parent
ef2c351696
commit
bd04451d58
@ -96,8 +96,35 @@ pub fn document(input: &str) -> Res<&str, Document> {
|
|||||||
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
let initial_context: ContextTree<'_, '_> = ContextTree::new();
|
||||||
let document_context =
|
let document_context =
|
||||||
initial_context.with_additional_node(ContextElement::DocumentRoot(input));
|
initial_context.with_additional_node(ContextElement::DocumentRoot(input));
|
||||||
let zeroth_section_matcher = parser_with_context!(zeroth_section)(&document_context);
|
let (remaining, document) = _document(&document_context, input)?;
|
||||||
let heading_matcher = parser_with_context!(heading)(&document_context);
|
{
|
||||||
|
// If there are radio targets in this document then we need to parse the entire document again with the knowledge of the radio targets.
|
||||||
|
let all_radio_targets: Vec<&Vec<Object<'_>>> = document
|
||||||
|
.iter_tokens()
|
||||||
|
.filter_map(|tkn| match tkn {
|
||||||
|
Token::Object(obj) => Some(obj),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter_map(|obj| match obj {
|
||||||
|
Object::RadioTarget(rt) => Some(rt),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|rt| &rt.children)
|
||||||
|
.collect();
|
||||||
|
if !all_radio_targets.is_empty() {
|
||||||
|
let document_context = document_context
|
||||||
|
.with_additional_node(ContextElement::RadioTarget(all_radio_targets));
|
||||||
|
let (remaining, document) = _document(&document_context, input)?;
|
||||||
|
return Ok((remaining, document));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((remaining, document))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
pub fn _document<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Document<'s>> {
|
||||||
|
let zeroth_section_matcher = parser_with_context!(zeroth_section)(context);
|
||||||
|
let heading_matcher = parser_with_context!(heading)(context);
|
||||||
let (remaining, _blank_lines) = many0(blank_line)(input)?;
|
let (remaining, _blank_lines) = many0(blank_line)(input)?;
|
||||||
let (remaining, zeroth_section) = opt(zeroth_section_matcher)(remaining)?;
|
let (remaining, zeroth_section) = opt(zeroth_section_matcher)(remaining)?;
|
||||||
let (remaining, children) = many0(heading_matcher)(remaining)?;
|
let (remaining, children) = many0(heading_matcher)(remaining)?;
|
||||||
@ -268,14 +295,13 @@ impl<'s> Document<'s> {
|
|||||||
|
|
||||||
impl<'s> Heading<'s> {
|
impl<'s> Heading<'s> {
|
||||||
pub fn iter_tokens<'r>(&'r self) -> impl Iterator<Item = Token<'r, 's>> {
|
pub fn iter_tokens<'r>(&'r self) -> impl Iterator<Item = Token<'r, 's>> {
|
||||||
self.title.iter().map(Token::Object).chain(self.children.iter().map(
|
self.title
|
||||||
|de| {
|
.iter()
|
||||||
match de {
|
.map(Token::Object)
|
||||||
DocumentElement::Heading(obj) => Token::Heading(obj),
|
.chain(self.children.iter().map(|de| match de {
|
||||||
DocumentElement::Section(obj) => Token::Section(obj),
|
DocumentElement::Heading(obj) => Token::Heading(obj),
|
||||||
}
|
DocumentElement::Section(obj) => Token::Section(obj),
|
||||||
}
|
}))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ pub enum ContextElement<'r, 's> {
|
|||||||
/// If any are found, this will force a 2nd parse through the
|
/// If any are found, this will force a 2nd parse through the
|
||||||
/// org-mode document since text needs to be re-parsed to look for
|
/// org-mode document since text needs to be re-parsed to look for
|
||||||
/// radio links matching the contents of radio targets.
|
/// radio links matching the contents of radio targets.
|
||||||
RadioTarget(Vec<Vec<Object<'s>>>),
|
RadioTarget(Vec<&'r Vec<Object<'s>>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExitMatcherNode<'r> {
|
pub struct ExitMatcherNode<'r> {
|
||||||
|
Loading…
Reference in New Issue
Block a user