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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use nom::branch::*;
use nom::character::complete::*;
#[cfg(feature = "trace")]
use nom::{AsBytes, Offset};
use nom::{IResult, InputIter, Needed, Slice};
use nom_locate::LocatedSpan;
use nom_tracable::{cumulative_histogram, histogram, tracable_parser, TracableInfo};
#[cfg(feature = "trace")]
use nom_tracable::{HasTracableInfo, Tracable};

#[derive(Clone)]
pub struct Span<'a>(LocatedSpan<&'a [u8], TracableInfo>);

#[cfg(feature = "trace")]
impl<'a> HasTracableInfo for Span<'a> {
    fn get_tracable_info(&self) -> TracableInfo {
        self.0.get_tracable_info()
    }

    fn set_tracable_info(mut self, info: TracableInfo) -> Self {
        self.0 = self.0.set_tracable_info(info);
        self
    }
}
#[cfg(feature = "trace")]
impl<'a> Tracable for Span<'a> {
    fn inc_depth(mut self) -> Self {
        self.0 = self.0.inc_depth();
        self
    }

    fn dec_depth(mut self) -> Self {
        self.0 = self.0.dec_depth();
        self
    }

    // Customize fragment format for &[u8]
    fn format(&self) -> String {
        let info = self.get_tracable_info();
        let fragment: String = String::from_utf8_lossy(self.0.fragment())
            .lines()
            .next()
            .unwrap_or_else(|| "")
            .chars()
            .take(info.fragment_width)
            .collect();
        format!("{:<8} : {}", self.0.location_offset(), fragment)
    }

    fn header(&self) -> String {
        self.0.header()
    }
}
impl<'a> InputIter for Span<'a> {
    type Item = u8;
    type Iter = std::iter::Enumerate<Self::IterElem>;
    type IterElem = std::iter::Copied<std::slice::Iter<'a, Self::Item>>;
    #[inline]
    fn iter_indices(&self) -> Self::Iter {
        self.0.iter_indices()
    }
    #[inline]
    fn iter_elements(&self) -> Self::IterElem {
        self.0.iter_elements()
    }
    #[inline]
    fn position<P>(&self, predicate: P) -> Option<usize>
    where
        P: Fn(Self::Item) -> bool,
    {
        self.0.position(predicate)
    }
    #[inline]
    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
        self.0.slice_index(count)
    }
}
impl<'a> Slice<std::ops::RangeFrom<usize>> for Span<'a> {
    fn slice(&self, range: std::ops::RangeFrom<usize>) -> Self {
        Span(self.0.slice(range))
    }
}

// Apply tracable_parser by custom attribute
#[tracable_parser]
pub fn expr(s: Span) -> IResult<Span, String> {
    alt((expr_plus, expr_minus, term))(s)
}

#[tracable_parser]
pub fn expr_plus(s: Span) -> IResult<Span, String> {
    let (s, x) = term(s)?;
    let (s, y) = char('+')(s)?;
    let (s, z) = expr(s)?;
    let ret = format!("{}{}{}", x, y, z);
    Ok((s, ret))
}

#[tracable_parser]
pub fn expr_minus(s: Span) -> IResult<Span, String> {
    let (s, x) = term(s)?;
    let (s, y) = char('-')(s)?;
    let (s, z) = expr(s)?;
    let ret = format!("{}{}{}", x, y, z);
    Ok((s, ret))
}

#[tracable_parser]
pub fn term(s: Span) -> IResult<Span, String> {
    let (s, x) = term_internal(s)?;
    Ok((s, x))
}

#[tracable_parser]
pub fn term_internal(s: Span) -> IResult<Span, String> {
    let (s, x) = char('1')(s)?;
    Ok((s, x.to_string()))
}

fn main() {
    // Configure trace setting
    let info = TracableInfo::new()
        .parser_width(64)
        .fragment_width(20)
        .fold("term");
    let _ret = expr(Span(LocatedSpan::new_extra("1-1+1+1-1".as_bytes(), info)));

    // Show histogram
    histogram();
    cumulative_histogram();
}