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 Transaction<'i> = super::Transaction<'i, Tracking>;
33pub type Posting<'i> = super::Posting<'i, Tracking>;
34pub type PostingAmount<'i> = super::PostingAmount<'i, Tracking>;
35pub type Lot<'i> = super::Lot<'i, Tracking>;
36
37/// Span of the tracked item within the original `&str`.
38/// Later one can convert this span into the range within the parsed str with
39/// [`ParsedSpan::resolve()`][crate::parse::ParsedSpan::resolve()].
40#[derive(Debug, PartialEq, Eq, Clone)]
41pub struct TrackedSpan(Range<usize>);
42
43impl TrackedSpan {
44    /// Returns the implementation of the span.
45    /// Note this is relative to the original string,
46    /// not the local index in the string.
47    pub(crate) fn as_range(&self) -> Range<usize> {
48        self.0.clone()
49    }
50
51    /// Creates an instance, only for unit test.
52    #[cfg(test)]
53    pub fn new(span: Range<usize>) -> TrackedSpan {
54        TrackedSpan(span)
55    }
56}
57
58/// Tracked provides the struct with maybe position tracking.
59#[derive(Debug, PartialEq, Eq)]
60pub struct Tracked<T> {
61    value: T,
62    span: TrackedSpan,
63}
64
65impl<T> AsUndecorated<T> for Tracked<T> {
66    fn as_undecorated(&self) -> &T {
67        &self.value
68    }
69}
70
71impl<T> Tracked<T> {
72    /// Returns span for the tracked position.
73    pub fn span(&self) -> TrackedSpan {
74        self.span.clone()
75    }
76
77    /// Wraps another value with the same span.
78    pub fn new(value: T, span: TrackedSpan) -> Self {
79        Self { value, span }
80    }
81}