1use core::cmp;
4use core::iter;
5
6use std::io;
7use std::rc::Rc;
8use std::collections::{BinaryHeap, HashMap};
9
10use crate::source::{ModuleSource, SourceText};
11use crate::debug::symbol::{DebugSymbol, ResolvedSymbol, TokenIndex};
12use crate::debug::symbol::errors::{SymbolResolutionError, ErrorKind};
13
14
15pub trait DebugSymbolResolver {
16 fn resolve_symbols<'s, S>(&self, symbols: S) -> io::Result<ResolvedSymbolTable<'s>> where S: Iterator<Item=&'s DebugSymbol>;
17}
18
19
20impl DebugSymbolResolver for ModuleSource {
21 fn resolve_symbols<'s, S>(&self, symbols: S) -> io::Result<ResolvedSymbolTable<'s>> where S: Iterator<Item=&'s DebugSymbol> {
22 match self.read_text()? {
23 SourceText::String(text) => Ok(resolve_debug_symbols(text.chars().map(Ok), symbols)),
24 SourceText::File(text) => Ok(resolve_debug_symbols(text, symbols))
25 }
26 }
27}
28
29pub struct BufferedResolver {
30 buffer: String,
31}
32
33impl BufferedResolver {
34 pub fn new(string: impl ToString) -> Self {
35 Self { buffer: string.to_string() }
36 }
37}
38
39impl DebugSymbolResolver for BufferedResolver {
40 fn resolve_symbols<'s, S>(&self, symbols: S) -> io::Result<ResolvedSymbolTable<'s>> where S: Iterator<Item=&'s DebugSymbol> {
41 Ok(resolve_debug_symbols(self.buffer.chars().map(Ok), symbols))
42 }
43}
44
45
46pub struct ResolvedSymbolTable<'s> {
47 table: HashMap<&'s DebugSymbol, Result<ResolvedSymbol, SymbolResolutionError>>,
48}
49
50impl<'s> iter::FromIterator<(&'s DebugSymbol, Result<ResolvedSymbol, SymbolResolutionError>)> for ResolvedSymbolTable<'s> {
51 fn from_iter<T>(iter: T) -> Self
52 where T: IntoIterator<Item=(&'s DebugSymbol, Result<ResolvedSymbol, SymbolResolutionError>)> {
53 Self {
54 table: HashMap::from_iter(iter)
55 }
56 }
57}
58
59impl<'s> ResolvedSymbolTable<'s> {
60 pub fn lookup(&self, symbol: &DebugSymbol) -> Option<Result<&ResolvedSymbol, &SymbolResolutionError>> {
61 self.table.get(symbol).map(|result| result.as_ref())
62 }
63
64 pub fn iter(&self) -> impl Iterator<Item=(&DebugSymbol, Result<&ResolvedSymbol, &SymbolResolutionError>)> {
65 self.table.iter().map(|(symbol, resolved)| (*symbol, resolved.as_ref()))
66 }
67
68 fn new() -> Self {
69 Self { table: HashMap::new() }
70 }
71
72 fn insert(&mut self, symbol: &'s DebugSymbol, result: Result<ResolvedSymbol, SymbolResolutionError>) {
73 self.table.insert(symbol, result);
74 }
75}
76
77
78fn resolve_debug_symbols<'s>(source: impl Iterator<Item=io::Result<char>>, symbols: impl Iterator<Item=&'s DebugSymbol>) -> ResolvedSymbolTable<'s> {
82 let mut dedup_symbols = symbols.collect::<Vec<&DebugSymbol>>();
84 dedup_symbols.dedup();
85
86 let mut next_symbols = BinaryHeap::new();
88 next_symbols.extend(dedup_symbols.into_iter().map(|sym| IndexSort(sym, SortIndex::Start)).map(cmp::Reverse));
89 let mut open_symbols = BinaryHeap::new();
92 let mut active_symbols = HashMap::<&DebugSymbol, (Vec<Rc<String>>, usize, usize)>::new(); let mut closing_symbols = HashMap::<&DebugSymbol, (Vec<Rc<String>>, usize, usize, usize)>::new();
94 let mut resolved_symbols = ResolvedSymbolTable::new();
95
96 let source = source.chain(iter::once(Ok(' ')));
98
99 let mut lineno = 1; let mut current_line = String::new();
101 for (char_result, index) in source.zip(0..) {
102 let c = match char_result {
104 Ok(c) => c,
105
106 Err(ioerror) => {
107 let ioerror = Rc::new(ioerror);
108
109 active_symbols.clear();
111 for cmp::Reverse(IndexSort(symbol,..)) in open_symbols.drain() {
112 let error = SymbolResolutionError::caused_by(*symbol, ioerror.clone());
113 resolved_symbols.insert(symbol, Err(error));
114 }
115
116 let error_rc = Rc::new(current_line.clone() + "...???");
119 for (symbol, (mut lines, lineno, start_index, end_index)) in closing_symbols.drain() {
120 lines.push(error_rc.clone());
121 let resolved = ResolvedSymbol::new(lines, lineno, start_index, end_index);
122 resolved_symbols.insert(symbol, Ok(resolved));
123 }
124
125 current_line.clear();
126 current_line += "???...";
127
128 break;
129 },
130 };
131
132 current_line.push(c);
134
135 while matches!(next_symbols.peek(), Some(&cmp::Reverse(IndexSort(sym,..))) if index == sym.start()) {
137 let symbol = next_symbols.pop().unwrap().0.0;
138
139 active_symbols.entry(symbol).or_insert_with(|| {
140 open_symbols.push(cmp::Reverse(IndexSort(symbol, SortIndex::End)));
141
142 let start_index = current_line.len() - 1;
143 (Vec::new(), lineno, start_index)
144 });
145 }
146
147 while matches!(open_symbols.peek(), Some(&cmp::Reverse(IndexSort(sym,..))) if index == sym.end()) {
149 let symbol = open_symbols.pop().unwrap().0.0;
150 if let Some((lines, lineno, start_index)) = active_symbols.remove(&symbol) {
151 closing_symbols.entry(symbol).or_insert_with(|| {
152
153 let total_len = lines.iter()
155 .map(|line| line.len())
156 .reduce(|acc, n| acc+n)
157 .unwrap_or(0);
158
159 let end_index = total_len + current_line.len() - 1;
160
161 (lines, lineno, start_index, end_index)
162 });
163 }
164 }
165
166 if c == '\n' {
168 lineno +=1; let line_rc = Rc::new(current_line.clone());
170
171 for (ref mut lines, ..) in active_symbols.values_mut() {
173 lines.push(Rc::clone(&line_rc));
174 }
175
176 for (symbol, (mut lines, lineno, start_index, end_index)) in closing_symbols.drain() {
178 lines.push(Rc::clone(&line_rc));
179
180 let resolved = ResolvedSymbol::new(lines, lineno, start_index, end_index);
181 resolved_symbols.insert(symbol, Ok(resolved));
182 }
183
184 current_line.clear();
186 }
187
188 if next_symbols.is_empty() && active_symbols.is_empty() && closing_symbols.is_empty() {
196 break;
197 }
198 }
199
200 for cmp::Reverse(IndexSort(symbol,..)) in open_symbols.drain() {
202 let error = SymbolResolutionError::new(*symbol, ErrorKind::EOFReached);
203 resolved_symbols.insert(symbol, Err(error));
204 }
205
206 let line_rc = Rc::new(current_line.clone());
207 for (symbol, (mut lines, lineno, start_index, end_index)) in closing_symbols.drain() {
208 lines.push(line_rc.clone());
209
210 let resolved = ResolvedSymbol::new(lines, lineno, start_index, end_index);
211 resolved_symbols.insert(symbol, Ok(resolved));
212 }
213
214 resolved_symbols
217}
218
219
220#[derive(Debug)]
221enum SortIndex { Start, End }
222
223#[derive(Debug)]
226struct IndexSort<'s>(&'s DebugSymbol, SortIndex);
227
228impl IndexSort<'_> {
229 fn sort_value(&self) -> TokenIndex {
230 match self.1 {
231 SortIndex::Start => self.0.start(),
232 SortIndex::End => self.0.end(),
233 }
234 }
235}
236
237impl PartialEq for IndexSort<'_> {
238 fn eq(&self, other: &Self) -> bool {
239 self.sort_value() == other.sort_value()
240 }
241}
242impl Eq for IndexSort<'_> { }
243
244impl PartialOrd for IndexSort<'_> {
245 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
246 Some(TokenIndex::cmp(&self.sort_value(), &other.sort_value()))
247 }
248}
249
250impl Ord for IndexSort<'_> {
251 fn cmp(&self, other: &Self) -> cmp::Ordering {
252 IndexSort::partial_cmp(self, other).unwrap()
253 }
254}