1use crate::quotes::{read_reference, DelimitedReferences, Reading};
2use nom::{
3 branch::alt,
4 bytes::complete::{tag, take_while, take_while1},
5 character::complete::{char, line_ending},
6 combinator::eof,
7 multi::{many0, many1},
8 sequence::{preceded, terminated},
9 IResult, Parser,
10};
11use std::cell::{OnceCell, RefCell};
12use std::collections::HashMap;
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Link {
16 pub id: Option<String>,
17 pub values: Vec<Link>,
18 pub children: Vec<Link>,
19 pub is_indented_id: bool,
20 pub nested: Option<Vec<Link>>,
23}
24
25impl Link {
26 pub fn new_singlet(id: String) -> Self {
27 Link {
28 id: Some(id),
29 values: vec![],
30 children: vec![],
31 is_indented_id: false,
32 nested: None,
33 }
34 }
35
36 pub fn new_indented_id(id: String) -> Self {
37 Link {
38 id: Some(id),
39 values: vec![],
40 children: vec![],
41 is_indented_id: true,
42 nested: None,
43 }
44 }
45
46 pub fn new_value(values: Vec<Link>) -> Self {
47 Link {
48 id: None,
49 values,
50 children: vec![],
51 is_indented_id: false,
52 nested: None,
53 }
54 }
55
56 pub fn new_link(id: Option<String>, values: Vec<Link>) -> Self {
57 Link {
58 id,
59 values,
60 children: vec![],
61 is_indented_id: false,
62 nested: None,
63 }
64 }
65
66 pub fn new_nested(body: Vec<Link>) -> Self {
69 Link {
70 id: None,
71 values: vec![],
72 children: vec![],
73 is_indented_id: false,
74 nested: Some(body),
75 }
76 }
77
78 pub fn with_children(mut self, children: Vec<Link>) -> Self {
79 self.children = children;
80 self
81 }
82}
83
84pub struct ParserState {
85 indentation_stack: RefCell<Vec<usize>>,
86 base_indentation: RefCell<Option<usize>>,
87 nested_depth: RefCell<usize>,
88 furthest: RefCell<FurthestFailure>,
89 unreadable_lines: RefCell<HashMap<LineKey, LineFailure>>,
90 references: OnceCell<DelimitedReferences>,
92}
93
94type LineKey = (usize, bool);
99
100type LineFailure = (usize, nom::error::ErrorKind);
103
104#[derive(Debug, Clone, Default)]
114struct FurthestFailure {
115 address: Option<usize>,
118 expected: Vec<&'static str>,
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct ParseFailure {
124 pub offset: usize,
126 pub expected: Vec<&'static str>,
130 pub kind: Option<nom::error::ErrorKind>,
134}
135
136pub struct SavedContext {
138 indentation_stack: Vec<usize>,
139 base_indentation: Option<usize>,
140}
141
142impl Default for ParserState {
143 fn default() -> Self {
144 Self::new()
145 }
146}
147
148impl ParserState {
149 pub fn new() -> Self {
150 ParserState {
151 indentation_stack: RefCell::new(vec![0]),
152 base_indentation: RefCell::new(None),
153 nested_depth: RefCell::new(0),
154 furthest: RefCell::new(FurthestFailure::default()),
155 unreadable_lines: RefCell::new(HashMap::new()),
156 references: OnceCell::new(),
157 }
158 }
159
160 pub fn set_base_indentation(&self, indent: usize) {
161 let mut base = self.base_indentation.borrow_mut();
162 if base.is_none() {
163 *base = Some(indent);
164 }
165 }
166
167 pub fn get_base_indentation(&self) -> usize {
168 self.base_indentation.borrow().unwrap_or(0)
169 }
170
171 pub fn normalize_indentation(&self, indent: usize) -> usize {
172 let base = self.get_base_indentation();
173 indent.saturating_sub(base)
174 }
175
176 pub fn push_indentation(&self, indent: usize) {
177 self.indentation_stack.borrow_mut().push(indent);
178 }
179
180 pub fn pop_indentation(&self) {
181 let mut stack = self.indentation_stack.borrow_mut();
182 if stack.len() > 1 {
183 stack.pop();
184 }
185 }
186
187 pub fn current_indentation(&self) -> usize {
188 *self.indentation_stack.borrow().last().unwrap_or(&0)
189 }
190
191 pub fn check_indentation(&self, indent: usize) -> bool {
192 indent >= self.current_indentation()
193 }
194
195 pub fn enter_nested_context(&self) -> SavedContext {
198 let saved = SavedContext {
199 indentation_stack: self.indentation_stack.replace(vec![0]),
200 base_indentation: self.base_indentation.replace(None),
201 };
202 *self.nested_depth.borrow_mut() += 1;
203 saved
204 }
205
206 pub fn exit_nested_context(&self, saved: SavedContext) {
208 *self.indentation_stack.borrow_mut() = saved.indentation_stack;
209 *self.base_indentation.borrow_mut() = saved.base_indentation;
210 let mut depth = self.nested_depth.borrow_mut();
211 if *depth > 0 {
212 *depth -= 1;
213 }
214 }
215
216 pub fn is_inside_nested_context(&self) -> bool {
217 *self.nested_depth.borrow() > 0
218 }
219
220 fn expected_at(&self, at: &str, what: &'static str) {
224 let address = at.as_ptr() as usize;
225 let mut furthest = self.furthest.borrow_mut();
226 match furthest.address {
227 Some(recorded) if recorded > address => {}
228 Some(recorded) if recorded == address => {
229 if !furthest.expected.contains(&what) {
230 furthest.expected.push(what);
231 }
232 }
233 _ => {
234 furthest.address = Some(address);
235 furthest.expected = vec![what];
236 }
237 }
238 }
239
240 fn failure(&self, document: &str, error: &nom::Err<nom::error::Error<&str>>) -> ParseFailure {
246 let base = document.as_ptr() as usize;
247 let (nom_offset, kind) = match error {
248 nom::Err::Error(e) | nom::Err::Failure(e) => (
249 (e.input.as_ptr() as usize).saturating_sub(base),
250 Some(e.code),
251 ),
252 nom::Err::Incomplete(_) => (document.len(), None),
253 };
254 let furthest = self.furthest.borrow();
255 let tracked = furthest
256 .address
257 .map(|address| address.saturating_sub(base))
258 .unwrap_or(0);
259 let offset = tracked.max(nom_offset).min(document.len());
260 let expected = if tracked == offset {
261 furthest.expected.clone()
262 } else {
263 Vec::new()
266 };
267 ParseFailure {
268 offset,
269 expected,
270 kind,
271 }
272 }
273}
274
275fn expected<'a, T>(
277 input: &'a str,
278 state: &ParserState,
279 what: &'static str,
280 kind: nom::error::ErrorKind,
281) -> IResult<&'a str, T> {
282 state.expected_at(input, what);
283 Err(nom::Err::Error(nom::error::Error::new(input, kind)))
284}
285
286pub(crate) fn is_whitespace_char(c: char) -> bool {
287 c == ' ' || c == '\t' || c == '\n' || c == '\r'
288}
289
290fn is_horizontal_whitespace(c: char) -> bool {
291 c == ' ' || c == '\t'
292}
293
294fn is_reference_char(c: char) -> bool {
295 !is_whitespace_char(c) && c != '(' && c != ':' && c != ')'
296}
297
298fn horizontal_whitespace(input: &str) -> IResult<&str, &str> {
299 take_while(is_horizontal_whitespace)(input)
300}
301
302fn whitespace(input: &str) -> IResult<&str, &str> {
303 take_while(is_whitespace_char)(input)
304}
305
306fn simple_reference(input: &str) -> IResult<&str, String> {
307 take_while1(is_reference_char)
308 .map(|s: &str| s.to_string())
309 .parse(input)
310}
311
312pub fn quoted_reference_end(document: &str, start: usize) -> Option<usize> {
319 let reading = read_reference(document.get(start..)?)?;
320 Some(start + reading.length)
321}
322
323fn delimited_reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
327 let references = state
328 .references
329 .get_or_init(|| DelimitedReferences::new(input));
330 match references.read(input) {
331 Some(Reading { value, length }) => Ok((&input[length..], value)),
332 None => Err(nom::Err::Error(nom::error::Error::new(
333 input,
334 nom::error::ErrorKind::Tag,
335 ))),
336 }
337}
338
339fn reference<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, String> {
340 let parsed = alt((|i| delimited_reference(i, state), simple_reference)).parse(input);
343 if parsed.is_err() {
344 state.expected_at(input, "a reference");
345 }
346 parsed
347}
348
349fn eol<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
350 let parsed = alt((
351 preceded(horizontal_whitespace, alt((line_ending, tag("\r")))),
352 preceded(horizontal_whitespace, eof),
353 |i| nested_group_end(i, state),
354 ))
355 .parse(input);
356 if parsed.is_err() {
357 state.expected_at(input, "end of line");
358 }
359 parsed
360}
361
362fn nested_group_end<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, &'a str> {
365 if !state.is_inside_nested_context() {
366 return Err(nom::Err::Error(nom::error::Error::new(
367 input,
368 nom::error::ErrorKind::Verify,
369 )));
370 }
371 let (rest, _) = horizontal_whitespace(input)?;
372 if rest.starts_with(')') {
373 Ok((rest, ""))
374 } else {
375 expected(rest, state, "\")\"", nom::error::ErrorKind::Char)
376 }
377}
378
379fn skip_empty_lines(input: &str) -> &str {
382 let mut rest = input;
383 loop {
384 let line_start = rest.trim_start_matches(is_horizontal_whitespace);
385 match strip_line_ending(line_start) {
386 Some(next) => rest = next,
387 None => return rest,
388 }
389 }
390}
391
392fn strip_line_ending(input: &str) -> Option<&str> {
393 input
394 .strip_prefix("\r\n")
395 .or_else(|| input.strip_prefix('\n'))
396 .or_else(|| input.strip_prefix('\r'))
397}
398
399fn reference_or_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
400 alt((
401 |i| nested_group(i, state),
402 (|i| reference(i, state)).map(Link::new_singlet),
403 ))
404 .parse(input)
405}
406
407fn single_line_value_and_whitespace<'a>(
408 input: &'a str,
409 state: &ParserState,
410) -> IResult<&'a str, Link> {
411 preceded(horizontal_whitespace, |i| reference_or_link(i, state)).parse(input)
412}
413
414fn single_line_values<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
415 many1(|i| single_line_value_and_whitespace(i, state)).parse(input)
416}
417
418fn single_line_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
419 let (input, _) = horizontal_whitespace(input)?;
420 let (input, id) = reference(input, state)?;
421 let (input, _) = horizontal_whitespace(input)?;
422 let (input, _) = colon(input, state)?;
423 let (input, values) = single_line_values(input, state)?;
424 Ok((input, Link::new_link(Some(id), values)))
425}
426
427fn colon<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
429 character(':', input, state, "\":\"")
430}
431
432fn character<'a>(
434 wanted: char,
435 input: &'a str,
436 state: &ParserState,
437 what: &'static str,
438) -> IResult<&'a str, char> {
439 let parsed: IResult<&'a str, char> = char(wanted).parse(input);
440 match parsed {
441 Ok(parsed) => Ok(parsed),
442 Err(_) => expected(input, state, what, nom::error::ErrorKind::Char),
443 }
444}
445
446fn single_line_value_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
447 (|i| single_line_values(i, state))
448 .map(Link::new_value)
449 .parse(input)
450}
451
452fn indented_id_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
453 let (input, id) = reference(input, state)?;
454 let (input, _) = horizontal_whitespace(input)?;
455 let (input, _) = colon(input, state)?;
456 let (input, _) = eol(input, state)?;
457 Ok((input, Link::new_indented_id(id)))
458}
459
460fn nested_group<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
464 let (body_input, _) = character('(', input, state, "\"(\"")?;
465 let saved = state.enter_nested_context();
466 let result = nested_group_body(body_input, state);
467 state.exit_nested_context(saved);
468 result
469}
470
471fn nested_group_body<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
472 if let Ok((rest, body)) = links(skip_empty_lines(input), state) {
473 let (rest, _) = whitespace(rest)?;
474 let (rest, _) = closing_parenthesis(rest, state)?;
475 return Ok((rest, Link::new_nested(body)));
476 }
477 let (rest, _) = whitespace(input)?;
478 let (rest, _) = closing_parenthesis(rest, state)?;
479 Ok((rest, Link::new_nested(vec![])))
480}
481
482fn closing_parenthesis<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, char> {
484 character(')', input, state, "\")\"")
485}
486
487fn single_line_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
488 alt((
489 terminated(|i| single_line_link(i, state), |i| eol(i, state)),
490 terminated(|i| single_line_value_link(i, state), |i| eol(i, state)),
491 ))
492 .parse(input)
493}
494
495fn any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
502 let key = (input.as_ptr() as usize, state.is_inside_nested_context());
503 if let Some(&(offset, kind)) = state.unreadable_lines.borrow().get(&key) {
504 return Err(nom::Err::Error(nom::error::Error::new(
505 &input[offset..],
506 kind,
507 )));
508 }
509 let parsed = read_any_link(input, state);
510 if let Err(nom::Err::Error(error)) = &parsed {
511 let offset = error.input.as_ptr() as usize - input.as_ptr() as usize;
512 state
513 .unreadable_lines
514 .borrow_mut()
515 .insert(key, (offset, error.code));
516 }
517 parsed
518}
519
520fn read_any_link<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
528 let (rest, group) = match nested_group(input, state) {
529 Ok(parsed) => parsed,
530 Err(_) if input.starts_with('(') => {
535 return reference(input, state).map(|(rest, id)| (rest, Link::new_singlet(id)))
536 }
537 Err(_) => {
538 return alt((
539 |i| indented_id_link(i, state),
540 |i| single_line_any_link(i, state),
541 ))
542 .parse(input)
543 }
544 };
545 if let Ok((rest, _)) = eol(rest, state) {
546 return Ok((rest, group));
547 }
548 let (rest, more) = many0(|i| single_line_value_and_whitespace(i, state)).parse(rest)?;
549 let (rest, _) = eol(rest, state)?;
550 let mut values = Vec::with_capacity(more.len() + 1);
551 values.push(group);
552 values.extend(more);
553 Ok((rest, Link::new_value(values)))
554}
555
556fn count_indentation(input: &str) -> IResult<&str, usize> {
557 take_while(|c| c == ' ').map(|s: &str| s.len()).parse(input)
558}
559
560fn push_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
561 let (input, spaces) = count_indentation(skip_empty_lines(input))?;
562 let normalized_spaces = state.normalize_indentation(spaces);
563 let current = state.current_indentation();
564
565 if normalized_spaces > current {
566 state.push_indentation(normalized_spaces);
567 Ok((input, ()))
568 } else {
569 Err(nom::Err::Error(nom::error::Error::new(
570 input,
571 nom::error::ErrorKind::Verify,
572 )))
573 }
574}
575
576fn check_indentation<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, ()> {
577 let (input, spaces) = count_indentation(input)?;
578 let normalized_spaces = state.normalize_indentation(spaces);
579
580 if state.check_indentation(normalized_spaces) {
581 Ok((input, ()))
582 } else {
583 Err(nom::Err::Error(nom::error::Error::new(
584 input,
585 nom::error::ErrorKind::Verify,
586 )))
587 }
588}
589
590fn element<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
591 let (input, link) = any_link(input, state)?;
592
593 let indentation = state.indentation_stack.borrow().clone();
594 if let Ok((child_input, _)) = push_indentation(input, state) {
595 if let Ok((rest, children)) = links(child_input, state) {
596 return Ok((rest, link.with_children(children)));
597 }
598 state.indentation_stack.replace(indentation);
601 }
602 Ok((input, link))
603}
604
605fn first_line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
606 let (input, spaces) = count_indentation(input)?;
609 state.set_base_indentation(spaces);
610 element(input, state)
611}
612
613fn line<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Link> {
614 preceded(|i| check_indentation(i, state), |i| element(i, state)).parse(skip_empty_lines(input))
616}
617
618fn links<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
619 let (input, first) = first_line(input, state)?;
620 let (input, rest) = many0(|i| line(i, state)).parse(input)?;
621
622 state.pop_indentation();
623
624 let mut result = vec![first];
625 result.extend(rest);
626 Ok((input, result))
627}
628
629pub fn parse_document(input: &str) -> IResult<&str, Vec<Link>> {
630 let state = ParserState::new();
631 document(input, &state)
632}
633
634pub fn parse_document_with_diagnostics(input: &str) -> Result<Vec<Link>, ParseFailure> {
641 let state = ParserState::new();
642 match document(input, &state) {
643 Ok((_, links)) => Ok(links),
644 Err(error) => Err(state.failure(input, &error)),
645 }
646}
647
648fn document<'a>(input: &'a str, state: &ParserState) -> IResult<&'a str, Vec<Link>> {
649 state
652 .references
653 .get_or_init(|| DelimitedReferences::new(input));
654
655 let document = skip_empty_lines(input);
657
658 if document.trim_matches(is_whitespace_char).is_empty() {
660 return Ok(("", vec![]));
661 }
662
663 let (rest, result) = links(document, state)?;
664 let (rest, _) = whitespace(rest)?;
665 let end: IResult<&'a str, &'a str> = eof(rest);
666 let (rest, _) = match end {
667 Ok(parsed) => parsed,
668 Err(_) => return expected(rest, state, "end of input", nom::error::ErrorKind::Eof),
669 };
670
671 Ok((rest, result))
672}