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> = Tracked<T>
14    where
15        T: AsUndecorated<T> + Debug + PartialEq + Eq;
16
17    fn decorate_parser<PIn, I, O, E>(parser: PIn) -> impl winnow::Parser<I, Self::Decorated<O>, E>
18    where
19        I: winnow::stream::Stream + winnow::stream::Location,
20        O: AsUndecorated<O> + Debug + PartialEq + Eq,
21        PIn: winnow::Parser<I, O, E>,
22    {
23        use winnow::Parser;
24        parser
25            .with_span()
26            .map(|(value, span)| Tracked::new(value, TrackedSpan(span)))
27    }
28}
29
30pub type LedgerEntry<'i> = super::LedgerEntry<'i, Tracking>;
31pub type Transaction<'i> = super::Transaction<'i, Tracking>;
32pub type Posting<'i> = super::Posting<'i, Tracking>;
33pub type PostingAmount<'i> = super::PostingAmount<'i, Tracking>;
34pub type Lot<'i> = super::Lot<'i, Tracking>;
35
36/// Span of the tracked position.
37/// Only useful within [ParsedContext][crate::parse::ParsedContext].
38#[derive(Debug, PartialEq, Eq, Clone)]
39pub struct TrackedSpan(Range<usize>);
40
41impl TrackedSpan {
42    /// Returns the implementation of the span.
43    /// Note this is relative to the original string,
44    /// not the local index in the string.
45    pub(crate) fn as_range(&self) -> Range<usize> {
46        self.0.clone()
47    }
48
49    /// Creates an instance, only for unit test.
50    #[cfg(test)]
51    pub fn new(span: Range<usize>) -> TrackedSpan {
52        TrackedSpan(span)
53    }
54}
55
56/// Tracked provides the struct with maybe position tracking.
57#[derive(Debug, PartialEq, Eq)]
58pub struct Tracked<T> {
59    value: T,
60    span: TrackedSpan,
61}
62
63impl<T> AsUndecorated<T> for Tracked<T> {
64    fn as_undecorated(&self) -> &T {
65        &self.value
66    }
67}
68
69impl<T> Tracked<T> {
70    /// Returns span for the tracked position.
71    pub fn span(&self) -> TrackedSpan {
72        self.span.clone()
73    }
74
75    /// Wraps another value with the same span.
76    pub fn new(value: T, span: TrackedSpan) -> Self {
77        Self { value, span }
78    }
79}