Skip to main content

okane_core/syntax/
tracked.rs

1//! Provides [Tracking] decoration, which attaches [Tracked] span information
2//! into syntax types so that report can raise error with the right position.
3
4use std::fmt::Debug;
5use std::ops::Range;
6
7use super::decoration::{AsUndecorated, Decoration};
8
9/// Tracking provides [Tracked] decoration for syntax types.
10pub struct Tracking;
11
12impl Decoration for Tracking {
13    type Decorated<T>
14        = Tracked<T>
15    where
16        T: AsUndecorated<T> + Debug + PartialEq + Eq;
17
18    fn decorate_parser<PIn, I, O, E>(parser: PIn) -> impl winnow::Parser<I, Self::Decorated<O>, E>
19    where
20        I: winnow::stream::Stream + winnow::stream::Location,
21        O: AsUndecorated<O> + Debug + PartialEq + Eq,
22        PIn: winnow::Parser<I, O, E>,
23    {
24        use winnow::Parser;
25        parser
26            .with_span()
27            .map(|(value, span)| Tracked::new(value, TrackedSpan(span)))
28    }
29}
30
31pub type LedgerEntry<'i> = super::LedgerEntry<'i, Tracking>;
32pub type LedgerStatement<'i> = super::LedgerStatement<'i, Tracking>;
33pub type Transaction<'i> = super::Transaction<'i, Tracking>;
34pub type Posting<'i> = super::Posting<'i, Tracking>;
35pub type PostingAmount<'i> = super::PostingAmount<'i, Tracking>;
36pub type Lot<'i> = super::Lot<'i, Tracking>;
37
38/// Span of the tracked item within the original `&str`.
39/// Later one can convert this span into the range within the parsed str with
40/// [`ParsedSpan::resolve()`][crate::parse::ParsedSpan::resolve()].
41#[derive(Debug, PartialEq, Eq, Clone)]
42pub struct TrackedSpan(Range<usize>);
43
44impl TrackedSpan {
45    /// Returns the implementation of the span.
46    /// Note this is relative to the original string,
47    /// not the local index in the string.
48    pub(crate) fn as_range(&self) -> Range<usize> {
49        self.0.clone()
50    }
51
52    /// Creates an instance, only for unit test.
53    #[cfg(test)]
54    pub fn new(span: Range<usize>) -> TrackedSpan {
55        TrackedSpan(span)
56    }
57}
58
59/// Tracked provides the struct with maybe position tracking.
60#[derive(Debug, PartialEq, Eq)]
61pub struct Tracked<T> {
62    value: T,
63    span: TrackedSpan,
64}
65
66impl<T> AsUndecorated<T> for Tracked<T> {
67    fn as_undecorated(&self) -> &T {
68        &self.value
69    }
70}
71
72impl<T> Tracked<T> {
73    /// Returns span for the tracked position.
74    pub fn span(&self) -> TrackedSpan {
75        self.span.clone()
76    }
77
78    /// Wraps another value with the same span.
79    pub fn new(value: T, span: TrackedSpan) -> Self {
80        Self { value, span }
81    }
82}