1#![deny(warnings)]
32#![deny(missing_docs)]
33#![deny(missing_debug_implementations)]
34
35extern crate pest;
36#[macro_use]
37extern crate pest_derive;
38
39use std::error;
40use std::fmt;
41use std::path::Path;
42
43use pest::Parser;
44
45mod parser;
46use self::parser::{BacktraceParser, Rule};
47
48#[derive(Debug)]
49pub struct Error<'a> {
51 inner: pest::Error<'a, Rule>,
52}
53
54impl<'a> fmt::Display for Error<'a> {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 fmt::Display::fmt(&self.inner, f)
57 }
58}
59
60impl<'a> error::Error for Error<'a> {}
61
62#[derive(Debug)]
63pub struct Backtrace<'a> {
65 pairs: pest::iterators::Pairs<'a, Rule>,
66}
67
68impl<'a> Backtrace<'a> {
69 pub fn parse(input: &'a str) -> Result<Backtrace<'a>, Error<'a>> {
72 let pairs =
73 BacktraceParser::parse(Rule::backtrace, input).map_err(|err| Error { inner: err })?;
74
75 Ok(Backtrace { pairs })
76 }
77
78 pub fn frames(&self) -> Frames<'a> {
80 Frames {
81 inner: self.pairs.clone(),
82 }
83 }
84}
85
86#[derive(Debug)]
87pub struct Frames<'a> {
89 inner: pest::iterators::Pairs<'a, Rule>,
90}
91
92impl<'a> Iterator for Frames<'a> {
93 type Item = Frame<'a>;
94
95 fn next(&mut self) -> Option<Self::Item> {
96 if let Some(frame) = self.inner.next() {
97 debug_assert!(frame.as_rule() == Rule::frame);
98 let mut frame_inner = frame.into_inner();
99
100 let frame_index = frame_inner.next().unwrap();
101 debug_assert!(frame_index.as_rule() == Rule::frame_index);
102 let frame_pointer = frame_inner.next().unwrap();
103 debug_assert!(frame_pointer.as_rule() == Rule::frame_pointer);
104
105 Some(Frame { pairs: frame_inner })
106 } else {
107 None
108 }
109 }
110}
111
112#[derive(Debug)]
113pub struct Frame<'a> {
115 pairs: pest::iterators::Pairs<'a, Rule>,
116}
117
118impl<'a> Frame<'a> {
119 pub fn symbols(&self) -> Symbols<'a> {
121 Symbols {
122 inner: self.pairs.clone(),
123 }
124 }
125}
126
127#[derive(Debug)]
128pub struct Symbols<'a> {
130 inner: pest::iterators::Pairs<'a, Rule>,
131}
132
133impl<'a> Iterator for Symbols<'a> {
134 type Item = Symbol<'a>;
135
136 fn next(&mut self) -> Option<Self::Item> {
137 if let Some(symbol) = self.inner.next() {
138 match symbol.as_rule() {
139 Rule::symbol_non_empty => {
140 let mut parsed_symbol = Symbol {
141 name: None,
142 filename: None,
143 lineno: None,
144 };
145 let mut symbol_inner = symbol.into_inner();
146 let symbol_name = symbol_inner.next().unwrap();
147 match symbol_name.as_rule() {
148 Rule::symbol_name_known => {
149 parsed_symbol.name = Some(symbol_name.into_span().as_str())
150 }
151 _ => {}
152 }
153 if let Some(symbol_location) = symbol_inner.next() {
154 debug_assert!(symbol_location.as_rule() == Rule::symbol_location);
155 let mut symbol_location_inner = symbol_location.into_inner();
156 let symbol_location_path = symbol_location_inner.next().unwrap();
157 debug_assert!(symbol_location_path.as_rule() == Rule::symbol_location_path);
158 parsed_symbol.filename =
159 Some(Path::new(symbol_location_path.into_span().as_str()));
160 let symbol_location_lineno = symbol_location_inner.next().unwrap();
161 debug_assert!(
162 symbol_location_lineno.as_rule() == Rule::symbol_location_lineno
163 );
164 parsed_symbol.lineno =
165 symbol_location_lineno.into_span().as_str().parse().ok();
166 }
167 Some(parsed_symbol)
168 }
169 _ => None,
170 }
171 } else {
172 None
173 }
174 }
175}
176
177#[derive(Debug)]
178pub struct Symbol<'a> {
180 name: Option<&'a str>,
181 filename: Option<&'a Path>,
182 lineno: Option<u32>,
183}
184
185impl<'a> Symbol<'a> {
186 pub fn name(&self) -> Option<&'a str> {
188 self.name
189 }
190
191 pub fn filename(&self) -> Option<&'a Path> {
193 self.filename
194 }
195
196 pub fn lineno(&self) -> Option<u32> {
198 self.lineno
199 }
200}