org_rust_parser/object/
footnote_ref.rs1use crate::constants::{COLON, NEWLINE, RBRACK, SPACE};
2use crate::node_pool::NodeID;
3use crate::parse::parse_object;
4use crate::types::{Cursor, MarkupKind, MatchError, ParseOpts, Parseable, Parser, Result};
5
6#[derive(Debug, Clone)]
10pub struct FootnoteRef<'a> {
11 pub label: Option<&'a str>,
12 pub children: Option<Vec<NodeID>>,
13}
14
15impl<'a> Parseable<'a> for FootnoteRef<'a> {
16 fn parse(
17 parser: &mut Parser<'a>,
18 mut cursor: Cursor<'a>,
19 parent: Option<NodeID>,
20 mut parse_opts: ParseOpts,
21 ) -> Result<NodeID> {
22 let start = cursor.index;
23 cursor.word("[fn:")?;
24
25 let label_match = cursor.fn_until(|chr| matches!(chr, NEWLINE | COLON | RBRACK | SPACE))?;
27 cursor.index = label_match.end;
28
29 match cursor.curr() {
30 RBRACK => {
31 if label_match.obj.is_empty() {
33 return Err(MatchError::InvalidLogic);
34 }
35
36 Ok(parser.alloc(
37 Self {
38 label: Some(label_match.obj),
39 children: None,
40 },
41 start,
42 cursor.index + 1,
43 parent,
44 ))
45 }
46 COLON => {
47 cursor.next();
48 parse_opts.from_object = false;
49 parse_opts.markup.insert(MarkupKind::FootnoteRef);
50
51 let mut content_vec: Vec<NodeID> = Vec::new();
52 loop {
54 let begin_def = cursor.index;
55 match parse_object(parser, cursor, parent, parse_opts) {
56 Ok(id) => {
57 cursor.index = parser.pool[id].end;
58 content_vec.push(id);
59 }
60 Err(MatchError::MarkupEnd(kind)) => {
61 if !kind.contains(MarkupKind::FootnoteRef) || cursor.index < start + 2 {
62 return Err(MatchError::InvalidLogic);
63 }
64
65 let new_id = parser.pool.reserve_id();
68 for id in content_vec.iter_mut() {
69 parser.pool[*id].parent = Some(new_id)
70 }
71
72 let ret_id = parser.alloc_with_id(
73 Self {
74 label: if label_match.obj.is_empty() {
75 None
76 } else {
77 Some(label_match.obj)
78 },
79 children: Some(content_vec),
80 },
81 start,
82 cursor.index + 1,
83 parent,
84 new_id,
85 );
86 if !label_match.obj.is_empty() {
87 parser.footnotes.insert(label_match.obj, ret_id);
88 }
89 return Ok(ret_id);
90 }
91 ret @ Err(_) => {
92 return ret;
93 }
94 }
95 }
96 }
97 _ => Err(MatchError::InvalidLogic),
98 }
99 }
100}