Skip to main content

links_notation/
parser.rs

1use crate::quotes::{DelimitedReferences, Reading, read_reference};
2use nom::{
3    IResult, Parser,
4    branch::alt,
5    bytes::complete::{tag, take_while, take_while1},
6    character::complete::{char, line_ending},
7    combinator::eof,
8    multi::{many0, many1},
9    sequence::{preceded, terminated},
10};
11use std::cell::{Cell, OnceCell, RefCell};
12use std::collections::HashMap;
13use std::ops::Range;
14
15#[derive(Debug, Clone, PartialEq)]
16pub struct Link {
17    pub id: Option<String>,
18    pub values: Vec<Link>,
19    pub children: Vec<Link>,
20    pub is_indented_id: bool,
21    /// Body of a parenthesized group, kept unflattened until the whole document
22    /// is transformed. `None` for every link that is not a parenthesized group.
23    pub nested: Option<Vec<Link>>,
24    /// Where the ID was written: the byte range of the reference, quotes,
25    /// escapes and literal syntax included, in the document that was parsed.
26    /// The parser reads a copy of the document with its comments blanked, which
27    /// keeps every byte where it was, so the range also locates the ID in the
28    /// document as the caller wrote it. `None` when the link has no ID.
29    pub id_span: Option<Range<usize>>,
30}
31
32impl Link {
33    pub fn new_singlet(id: String) -> Self {
34        Link {
35            id: Some(id),
36            values: vec![],
37            children: vec![],
38            is_indented_id: false,
39            nested: None,
40            id_span: None,
41        }
42    }
43
44    pub fn new_indented_id(id: String) -> Self {
45        Link {
46            id: Some(id),
47            values: vec![],
48            children: vec![],
49            is_indented_id: true,
50            nested: None,
51            id_span: None,
52        }
53    }
54
55    pub fn new_value(values: Vec<Link>) -> Self {
56        Link {
57            id: None,
58            values,
59            children: vec![],
60            is_indented_id: false,
61            nested: None,
62            id_span: None,
63        }
64    }
65
66    pub fn new_link(id: Option<String>, values: Vec<Link>) -> Self {
67        Link {
68            id,
69            values,
70            children: vec![],
71            is_indented_id: false,
72            nested: None,
73            id_span: None,
74        }
75    }
76
77    /// Creates a link that stands for a parenthesized group, keeping the links
78    /// parsed inside the parentheses as they were written.
79    pub fn new_nested(body: Vec<Link>) -> Self {
80        Link {
81            id: None,
82            values: vec![],
83            children: vec![],
84            is_indented_id: false,
85            nested: Some(body),
86            id_span: None,
87        }
88    }
89
90    pub fn with_children(mut self, children: Vec<Link>) -> Self {
91        self.children = children;
92        self
93    }
94
95    /// The same link, recording where its ID was written.
96    pub fn with_id_span(mut self, span: Range<usize>) -> Self {
97        self.id_span = Some(span);
98        self
99    }
100}
101
102/// How deep links may nest when nothing says otherwise.
103///
104/// Every level of nesting is a level of recursion, so the limit is what keeps a
105/// deeply nested document from overflowing the stack, which aborts the process
106/// instead of returning an error. It is set well below what fits: in a debug
107/// build a group written where a value goes, as in `(a (a (a b)))`, costs about
108/// 24 KB of stack a level, so a spawned thread's 2 MiB holds only 86 of them.
109/// The same limit applies in every Links Notation implementation.
110pub const DEFAULT_MAX_DEPTH: usize = 64;
111
112pub struct ParserState {
113    indentation_stack: RefCell<Vec<usize>>,
114    base_indentation: RefCell<Option<usize>>,
115    nested_depth: RefCell<usize>,
116    /// Nesting depth of the level-zero lines of the current context: the number
117    /// of groups and indentation levels that enclose it.
118    context_depth: RefCell<usize>,
119    max_depth: usize,
120    /// Where the document first nested deeper than `max_depth`, as an address
121    /// into the document being parsed.
122    too_deep: RefCell<Option<usize>>,
123    furthest: RefCell<FurthestFailure>,
124    unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
125    /// The delimited references of the document being parsed.
126    references: OnceCell<DelimitedReferences>,
127    /// Address of the first byte of the document being parsed, which turns the
128    /// part of the document a reference was read from into a byte range.
129    document_start: Cell<usize>,
130}
131
132/// Where a line starts, as an address into the document, and whether it is
133/// inside a parenthesized group. Reading a line depends on nothing else: a group
134/// starts a fresh indentation context, and indentation only decides which lines
135/// become children, so a line that could not be read once never can be.
136type LineKey = (usize, bool);
137
138/// How far past the start of an unreadable line the parser failed, and the
139/// `nom` error kind it failed with.
140type LineFailure = (usize, nom::error::ErrorKind);
141
142/// The furthest position any alternative reached before failing, and what could
143/// have continued the document there.
144///
145/// The parser backtracks, so the position the last alternative happens to fail
146/// at says little about where the document stops making sense: a defect in the
147/// middle of line two is reported by `nom` as "expected end of input" at the
148/// start of line two, because that is where the document last parsed cleanly.
149/// The furthest position reached is what a PEG parser points at, and it is what
150/// the JavaScript port reports.
151#[derive(Debug, Clone, Default)]
152struct FurthestFailure {
153    /// Address of the furthest failing position, as a pointer into the document
154    /// being parsed. Turned into an offset once the document is at hand again.
155    address: Option<usize>,
156    expected: Vec<&'static str>,
157}
158
159/// Where the parser stopped, and what it could have accepted there.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct ParseFailure {
162    /// Byte offset into the document the parser stopped at.
163    pub offset: usize,
164    /// What could have continued the document at `offset`, in the wording used
165    /// by the error message. Empty when the failure came from a place that
166    /// names no expectation.
167    pub expected: Vec<&'static str>,
168    /// The `nom` error kind. An internal detail of this parser: it says which
169    /// combinator gave up, not what is wrong with the document, so it is kept
170    /// out of the error message and reachable only through `Debug`.
171    pub kind: Option<nom::error::ErrorKind>,
172    /// The maximum nesting depth when the document nests deeper than it, which
173    /// `offset` then points at; `None` for every other failure.
174    pub max_depth_exceeded: Option<usize>,
175}
176
177/// Indentation state of the context a parenthesized group was opened in.
178pub struct SavedContext {
179    indentation_stack: Vec<usize>,
180    base_indentation: Option<usize>,
181    context_depth: usize,
182}
183
184impl Default for ParserState {
185    fn default() -> Self {
186        Self::new()
187    }
188}
189
190impl ParserState {
191    pub fn new() -> Self {
192        Self::with_max_depth(DEFAULT_MAX_DEPTH)
193    }
194
195    /// A parser state that refuses links nested deeper than `max_depth`.
196    pub fn with_max_depth(max_depth: usize) -> Self {
197        ParserState {
198            indentation_stack: RefCell::new(vec![0]),
199            base_indentation: RefCell::new(None),
200            nested_depth: RefCell::new(0),
201            context_depth: RefCell::new(0),
202            max_depth,
203            too_deep: RefCell::new(None),
204            furthest: RefCell::new(FurthestFailure::default()),
205            unreadable_lines: RefCell::new(HashMap::new()),
206            references: OnceCell::new(),
207            document_start: Cell::new(0),
208        }
209    }
210
211    pub fn set_base_indentation(&self, indent: usize) {
212        let mut base = self.base_indentation.borrow_mut();
213        if base.is_none() {
214            *base = Some(indent);
215        }
216    }
217
218    pub fn get_base_indentation(&self) -> usize {
219        self.base_indentation.borrow().unwrap_or(0)
220    }
221
222    pub fn normalize_indentation(&self, indent: usize) -> usize {
223        let base = self.get_base_indentation();
224        indent.saturating_sub(base)
225    }
226
227    pub fn push_indentation(&self, indent: usize) {
228        self.indentation_stack.borrow_mut().push(indent);
229    }
230
231    pub fn pop_indentation(&self) {
232        let mut stack = self.indentation_stack.borrow_mut();
233        if stack.len() > 1 {
234            stack.pop();
235        }
236    }
237
238    pub fn current_indentation(&self) -> usize {
239        *self.indentation_stack.borrow().last().unwrap_or(&0)
240    }
241
242    pub fn check_indentation(&self, indent: usize) -> bool {
243        indent >= self.current_indentation()
244    }
245
246    /// Opens a nested context: the group body starts fresh at indentation level
247    /// zero and follows the same rules as the root document.
248    pub fn enter_nested_context(&self) -> SavedContext {
249        let depth = self.depth() + 1;
250        let saved = SavedContext {
251            indentation_stack: self.indentation_stack.replace(vec![0]),
252            base_indentation: self.base_indentation.replace(None),
253            context_depth: self.context_depth.replace(depth),
254        };
255        *self.nested_depth.borrow_mut() += 1;
256        saved
257    }
258
259    /// Restores the context the parenthesized group was opened in.
260    pub fn exit_nested_context(&self, saved: SavedContext) {
261        *self.indentation_stack.borrow_mut() = saved.indentation_stack;
262        *self.base_indentation.borrow_mut() = saved.base_indentation;
263        *self.context_depth.borrow_mut() = saved.context_depth;
264        let mut depth = self.nested_depth.borrow_mut();
265        if *depth > 0 {
266            *depth -= 1;
267        }
268    }
269
270    pub fn is_inside_nested_context(&self) -> bool {
271        *self.nested_depth.borrow() > 0
272    }
273
274    /// Nesting depth of the line being parsed: every enclosing parenthesized
275    /// group and every indentation level counts as one.
276    pub fn depth(&self) -> usize {
277        *self.context_depth.borrow() + self.indentation_stack.borrow().len() - 1
278    }
279
280    /// Fails for good when `depth` is deeper than the parser allows, so that
281    /// no alternative goes on to recurse any further. `at` is where the level
282    /// that is one too deep opens.
283    fn check_depth<'a>(&self, at: &'a str, depth: usize) -> IResult<&'a str, ()> {
284        if depth <= self.max_depth {
285            return Ok((at, ()));
286        }
287        self.too_deep
288            .borrow_mut()
289            .get_or_insert(at.as_ptr() as usize);
290        Err(nom::Err::Failure(nom::error::Error::new(
291            at,
292            nom::error::ErrorKind::TooLarge,
293        )))
294    }
295
296    /// Records that `what` could have continued the document at `at`, and that
297    /// nothing there did. Only the furthest such position is kept; every
298    /// expectation recorded at that same position is kept alongside it.
299    fn expected_at(&self, at: &str, what: &'static str) {
300        let address = at.as_ptr() as usize;
301        let mut furthest = self.furthest.borrow_mut();
302        match furthest.address {
303            Some(recorded) if recorded > address => {}
304            Some(recorded) if recorded == address => {
305                if !furthest.expected.contains(&what) {
306                    furthest.expected.push(what);
307                }
308            }
309            _ => {
310                furthest.address = Some(address);
311                furthest.expected = vec![what];
312            }
313        }
314    }
315
316    /// Turns everything recorded during a failed parse into a position in
317    /// `document`.
318    ///
319    /// `nom`'s own error position is the fallback and the floor: the parser
320    /// reached at least that far, whatever the tracked alternatives say.
321    fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
322        let base = document.as_ptr() as usize;
323        let (nom_offset, kind) = match error {
324            nom::Err::Error(e) | nom::Err::Failure(e) => (
325                (e.input.as_ptr() as usize).saturating_sub(base),
326                Some(e.code),
327            ),
328            nom::Err::Incomplete(_) => (document.len(), None),
329        };
330        if let Some(address) = *self.too_deep.borrow() {
331            return ParseFailure {
332                offset: address.saturating_sub(base).min(document.len()),
333                expected: Vec::new(),
334                kind,
335                max_depth_exceeded: Some(self.max_depth),
336            };
337        }
338        let furthest = self.furthest.borrow();
339        let tracked = furthest
340            .address
341            .map(|address| address.saturating_sub(base))
342            .unwrap_or(0);
343        let offset = tracked.max(nom_offset).min(document.len());
344        let expected = if tracked == offset {
345            furthest.expected.clone()
346        } else {
347            // The tracked expectations belong to an earlier position, so they
348            // do not describe the place being reported.
349            Vec::new()
350        };
351        ParseFailure {
352            offset,
353            expected,
354            kind,
355            max_depth_exceeded: None,
356        }
357    }
358}
359
360/// Fails the way `nom` does, after recording what was expected at `input`.
361fn expected<'a, T>(
362    input: &'a str,
363    state: &ParserState,
364    what: &'static str,
365    kind: nom::error::ErrorKind,
366) -> IResult<&'a str, T> {
367    state.expected_at(input, what);
368    Err(nom::Err::Error(nom::error::Error::new(input, kind)))
369}
370
371pub(crate) fn is_whitespace_char(c: char) -> bool {
372    c == ' ' || c == '\t' || c == '\n' || c == '\r'
373}
374
375fn is_horizontal_whitespace(c: char) -> bool {
376    c == ' ' || c == '\t'
377}
378
379fn is_reference_char(c: char) -> bool {
380    !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
381}
382
383fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
384    take_while(is_horizontal_whitespace)(input)
385}
386
387fn whitespace(input: &str) -> IResult<&str, &str> {
388    take_while(is_whitespace_char)(input)
389}
390
391fn simple_reference(input: &str) -> IResult<&str, String> {
392    take_while1(is_reference_char)
393        .map(|s: &str| s.to_string())
394        .parse(input)
395}
396
397/// The offset just past the delimited reference that starts at `start`, or
398/// `None` when nothing that far into `document` opens one.
399///
400/// Comment stripping needs to know how far a delimited reference reaches so
401/// that a `#` written inside one stays content, and it has to agree with the
402/// parser about it, which is why both read references the same way.
403pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
404    let reading = read_reference(document.get(start..)?)?;
405    Some(start + reading.length)
406}
407
408/// A delimited reference with any number of delimiters. A run of an even
409/// number of delimiters that does not open a reference with a substantive body
410/// is the empty reference.
411fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
412    let references = state
413        .references
414        .get_or_init(|| DelimitedReferences::new(input));
415    match references.read(input) {
416        Some(Reading { value, length }) => Ok((&input[length..], value)),
417        None => Err(nom::Err::Error(nom::error::Error::new(
418            input,
419            nom::error::ErrorKind::Tag,
420        ))),
421    }
422}
423
424fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
425    if let Some(prefix) = crate::reference_literal::prefix_end(input) {
426        if let Some(closing) = input[prefix..].find('}') {
427            let length = prefix + closing + 1;
428            if let Ok(value) = crate::decode_reference_literal(&input[..length]) {
429                return Ok((&input[length..], value));
430            }
431        }
432        state.expected_at(input, "a valid version 1 reference literal");
433        return Err(nom::Err::Failure(nom::error::Error::new(
434            input,
435            nom::error::ErrorKind::Tag,
436        )));
437    }
438    // Try quoted strings with dynamic quote detection (supports any N quotes)
439    // Then fall back to simple unquoted reference
440    let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
441    if parsed.is_err() {
442        state.expected_at(input, "a reference");
443    }
444    parsed
445}
446
447/// A reference together with the byte range it was written at, so that a link
448/// can say how its ID was written.
449fn spanned_reference<'a>(
450    input: &'a str,
451    state: &ParserState,
452) -> IResult<&'a str, (String, Range<usize>)> {
453    let (rest, value) = reference(input, state)?;
454    let start = (input.as_ptr() as usize).saturating_sub(state.document_start.get());
455    let end = start + (input.len() - rest.len());
456    Ok((rest, (value, start..end)))
457}
458
459fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
460    let parsed = alt((
461        preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
462        preceded(horizontal_whitespace, eof),
463        |i| nested_group_end(i, state),
464    ))
465    .parse(input);
466    if parsed.is_err() {
467        state.expected_at(input, "end of line");
468    }
469    parsed
470}
471
472/// Inside a parenthesized group the closing parenthesis ends the last line,
473/// just like a line break does at the root.
474fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
475    if !state.is_inside_nested_context() {
476        return Err(nom::Err::Error(nom::error::Error::new(
477            input,
478            nom::error::ErrorKind::Verify,
479        )));
480    }
481    let (rest, _) = horizontal_whitespace(input)?;
482    if rest.starts_with(')') {
483        Ok((rest, ""))
484    } else {
485        expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
486    }
487}
488
489/// Skips the line breaks and blank lines that separate `(` from the first line
490/// of the group body.
491fn skip_empty_lines(input: &str) -> &str {
492    let mut rest = input;
493    loop {
494        let line_start = rest.trim_start_matches(is_horizontal_whitespace);
495        match strip_line_ending(line_start) {
496            Some(next) => rest = next,
497            None => return rest,
498        }
499    }
500}
501
502fn strip_line_ending(input: &str) -> Option<&str> {
503    input
504        .strip_prefix("\r\n")
505        .or_else(|| input.strip_prefix('\n'))
506        .or_else(|| input.strip_prefix('\r'))
507}
508
509fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
510    alt((
511        |i| nested_group(i, state),
512        (|i| spanned_reference(i, state))
513            .map(|(id, span)| Link::new_singlet(id).with_id_span(span)),
514    ))
515    .parse(input)
516}
517
518fn single_line_value_and_whitespace<'a>(
519    input: &'a str,
520    state: &ParserState,
521) -> IResult<&'a str, Link> {
522    preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
523}
524
525fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
526    many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
527}
528
529fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
530    let (input, _) = horizontal_whitespace(input)?;
531    let (input, (id, span)) = spanned_reference(input, state)?;
532    let (input, _) = horizontal_whitespace(input)?;
533    let (input, _) = colon(input, state)?;
534    let (input, values) = single_line_values(input, state)?;
535    Ok((input, Link::new_link(Some(id), values).with_id_span(span)))
536}
537
538/// The colon that separates an identifier from its values.
539fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
540    character(':', input, state, "\":\"")
541}
542
543/// Matches one character, recording what was expected when it is not there.
544fn character<'a>(
545    wanted: char,
546    input: &'a str,
547    state: &ParserState,
548    what: &'static str,
549) -> IResult<&'a str, char> {
550    let parsed: IResult<&'a str, char> = char(wanted).parse(input);
551    match parsed {
552        Ok(parsed) => Ok(parsed),
553        Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
554    }
555}
556
557fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
558    (|i| single_line_values(i, state))
559        .map(Link::new_value)
560        .parse(input)
561}
562
563fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
564    let (input, (id, span)) = spanned_reference(input, state)?;
565    let (input, _) = horizontal_whitespace(input)?;
566    let (input, _) = colon(input, state)?;
567    let (input, _) = eol(input, state)?;
568    Ok((input, Link::new_indented_id(id).with_id_span(span)))
569}
570
571/// A parenthesized group opens a nested context: its body starts fresh at
572/// indentation level zero and is parsed with the same rules as the root
573/// document, so indentation is structural inside parentheses as well.
574fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
575    let (body_input, _) = character('(', input, state, "\"(\"")?;
576    state.check_depth(input, state.depth() + 1)?;
577    let saved = state.enter_nested_context();
578    let result = nested_group_body(body_input, state);
579    state.exit_nested_context(saved);
580    result
581}
582
583fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
584    match links(skip_empty_lines(input), state) {
585        Ok((rest, body)) => {
586            let (rest, _) = whitespace(rest)?;
587            let (rest, _) = closing_parenthesis(rest, state)?;
588            return Ok((rest, Link::new_nested(body)));
589        }
590        Err(failure @ nom::Err::Failure(_)) => return Err(failure),
591        Err(_) => {}
592    }
593    let (rest, _) = whitespace(input)?;
594    let (rest, _) = closing_parenthesis(rest, state)?;
595    Ok((rest, Link::new_nested(vec![])))
596}
597
598/// The parenthesis that closes a group.
599fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
600    character(')', input, state, "\")\"")
601}
602
603fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
604    alt((
605        terminated(|i| single_line_link(i, state), |i| eol(i, state)),
606        terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
607    ))
608    .parse(input)
609}
610
611/// Reads one line, or fails at once when the line was already found unreadable.
612///
613/// A line that does not parse as the first child of the line above it is tried
614/// again as a sibling at every enclosing indentation level. When the line holds
615/// a group, each of those attempts reads the whole group again, so without this
616/// the work doubles with every indented level (issue #314).
617fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
618    let key = (input.as_ptr() as usize, state.is_inside_nested_context());
619    if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
620        return Err(nom::Err::Error(nom::error::Error::new(
621            &input[offset..],
622            kind,
623        )));
624    }
625    let parsed = read_any_link(input, state);
626    if let Err(nom::Err::Error(error)) = &parsed {
627        let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
628        state
629            .unreadable_lines
630            .borrow_mut()
631            .insert(key, (offset, error.code));
632    }
633    parsed
634}
635
636/// A line that starts with a parenthesized group reads that group once and then
637/// branches on what follows it: the end of the line makes the group the whole
638/// link, and more values make it the first value of a value link.
639///
640/// Every other alternative would have to read the group again, which doubles
641/// the work at each level of nesting and makes a few dozen bytes take seconds
642/// ([#314](https://github.com/link-foundation/links-notation/issues/314)).
643fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
644    let (rest, group) = match nested_group(input, state) {
645        Ok(parsed) => parsed,
646        // Neither an indented ID nor a single-line link can start with a
647        // parenthesis, and a value link would begin with this same group, so
648        // nothing else can read a line that opens one. Report it the way the
649        // single-line value link does, as a missing reference.
650        Err(_) if input.starts_with('(') => {
651            return spanned_reference(input, state)
652                .map(|(rest, (id, span))| (rest, Link::new_singlet(id).with_id_span(span)));
653        }
654        Err(_) => {
655            return alt((
656                |i| indented_id_link(i, state),
657                |i| single_line_any_link(i, state),
658            ))
659            .parse(input);
660        }
661    };
662    if let Ok((rest, _)) = eol(rest, state) {
663        return Ok((rest, group));
664    }
665    let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
666    let (rest, _) = eol(rest, state)?;
667    let mut values = Vec::with_capacity(more.len() + 1);
668    values.push(group);
669    values.extend(more);
670    Ok((rest, Link::new_value(values)))
671}
672
673fn count_indentation(input: &str) -> IResult<&str, usize> {
674    take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
675}
676
677fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
678    let (input, spaces) = count_indentation(skip_empty_lines(input))?;
679    let normalized_spaces = state.normalize_indentation(spaces);
680    let current = state.current_indentation();
681
682    if normalized_spaces > current {
683        state.push_indentation(normalized_spaces);
684        Ok((input, ()))
685    } else {
686        Err(nom::Err::Error(nom::error::Error::new(
687            input,
688            nom::error::ErrorKind::Verify,
689        )))
690    }
691}
692
693fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
694    let (input, spaces) = count_indentation(input)?;
695    let normalized_spaces = state.normalize_indentation(spaces);
696
697    if state.check_indentation(normalized_spaces) {
698        Ok((input, ()))
699    } else {
700        Err(nom::Err::Error(nom::error::Error::new(
701            input,
702            nom::error::ErrorKind::Verify,
703        )))
704    }
705}
706
707fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
708    let start = input;
709    let (input, link) = any_link(input, state)?;
710    // Only a line that parsed counts, so trailing spaces indented past the limit
711    // are still read as the whitespace they are.
712    state.check_depth(start, state.depth())?;
713
714    let indentation = state.indentation_stack.borrow().clone();
715    if let Ok((child_input, _)) = push_indentation(input, state) {
716        match links(child_input, state) {
717            Ok((rest, children)) => return Ok((rest, link.with_children(children))),
718            Err(failure @ nom::Err::Failure(_)) => return Err(failure),
719            Err(_) => {}
720        }
721        // No child line followed the indentation. Backtrack to the link so
722        // the document can consume the remaining spaces as whitespace.
723        state.indentation_stack.replace(indentation);
724    }
725    Ok((input, link))
726}
727
728fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
729    // Set base indentation from the first line and consume it, so that the first
730    // line is parsed exactly like every following line.
731    let (input, spaces) = count_indentation(input)?;
732    state.set_base_indentation(spaces);
733    element(input, state)
734}
735
736fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
737    // Blank lines do not break a document, they are simply skipped
738    preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
739}
740
741fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
742    let (input, first) = first_line(input, state)?;
743    let (input, rest) = many0(|i| line(i, state)).parse(input)?;
744
745    state.pop_indentation();
746
747    let mut result = vec![first];
748    result.extend(rest);
749    Ok((input, result))
750}
751
752pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
753    let state = ParserState::new();
754    document(input, &state)
755}
756
757/// Parses a document and, when it does not parse, says where it stopped.
758///
759/// `parse_document` reports a failure the way `nom` does: with the whole
760/// unconsumed remainder of the input and the combinator that gave up. Neither
761/// tells a reader which line to look at, and the remainder grows with the size
762/// of the document. This is the entry point the library uses.
763pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
764    parse_document_with_max_depth(input, DEFAULT_MAX_DEPTH)
765}
766
767/// Parses a document the way [`parse_document_with_diagnostics`] does, refusing
768/// links nested deeper than `max_depth`. Every parenthesized group and every
769/// indentation level is one level of nesting.
770pub fn parse_document_with_max_depth(
771    input: &str,
772    max_depth: usize,
773) -> Result<Vec<Link>, ParseFailure> {
774    let state = ParserState::with_max_depth(max_depth);
775    match document(input, &state) {
776        Ok((_, links)) => Ok(links),
777        Err(error) => Err(state.failure(input, &error)),
778    }
779}
780
781fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
782    // Every reference is read from a part of this document, so the runs of
783    // delimiters are listed from all of it.
784    state
785        .references
786        .get_or_init(|| DelimitedReferences::new(input));
787    state.document_start.set(input.as_ptr() as usize);
788
789    // Skip leading blank lines but preserve the line structure
790    let document = skip_empty_lines(input);
791
792    // Handle empty or whitespace-only documents
793    if document.trim_matches(is_whitespace_char).is_empty() {
794        return Ok(("", vec![]));
795    }
796
797    let (rest, result) = links(document, state)?;
798    let (rest, _) = whitespace(rest)?;
799    let end: IResult<&'a str, &'a str> = eof(rest);
800    let (rest, _) = match end {
801        Ok(parsed) => parsed,
802        Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
803    };
804
805    Ok((rest, result))
806}