1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use crate::core::pos::Pos;
use crate::core::span::Span;
use crate::error::error_printer::{base_report, ErrorLabel};
use crate::error::ParseError;
use ariadne::{Label, Report};
use itertools::Itertools;
use std::cmp::max;
use std::collections::HashSet;

/// Set error keeps track of the set of labels at the furthest position.
#[derive(Clone)]
pub struct SetError<'grm> {
    pub span: Span,
    pub labels: HashSet<ErrorLabel<'grm>>,
    pub explicit: bool,
}

impl<'grm> ParseError for SetError<'grm> {
    type L = ErrorLabel<'grm>;

    fn new(span: Span) -> Self {
        Self {
            span,
            labels: HashSet::new(),
            explicit: false,
        }
    }

    fn add_label_explicit(&mut self, label: Self::L) {
        if !self.explicit {
            self.explicit = true;
            self.labels.clear();
        }
        self.labels.insert(label);
    }

    fn add_label_implicit(&mut self, label: Self::L) {
        if self.explicit {
            return;
        }
        self.labels.insert(label);
    }

    fn merge(mut self, other: Self) -> Self {
        assert_eq!(self.span.start, other.span.start);
        for e in other.labels {
            self.labels.insert(e);
        }
        Self {
            span: Span::new(self.span.start, max(self.span.end, other.span.end)),
            labels: self.labels,
            explicit: self.explicit || other.explicit,
        }
    }

    fn set_end(&mut self, end: Pos) {
        self.span.end = end;
    }

    fn report(&self, enable_debug: bool) -> Report<'static, Span> {
        let mut report = base_report(self.span);

        //Add labels
        for (start, labels) in self
            .labels
            .iter()
            .filter(|l| enable_debug || !l.is_debug())
            .into_group_map_by(|l| l.span().start)
            .into_iter()
        {
            report = report.with_label(
                Label::new(start.span_to(start))
                    .with_message(format!("Tried parsing {}", labels.into_iter().format(" / ")))
                    .with_order(-(<Pos as Into<usize>>::into(start) as i32)),
            );
        }

        report.finish()
    }
}