Skip to content

Instantly share code, notes, and snippets.

@marcusklaas
Created August 16, 2015 20:17
Show Gist options
  • Save marcusklaas/1ce0906ec080ff8ece70 to your computer and use it in GitHub Desktop.
Save marcusklaas/1ce0906ec080ff8ece70 to your computer and use it in GitHub Desktop.
pub struct ListItems<'a, I, F1, F2, F3>
where I: Iterator
{
codemap: &'a CodeMap,
inner: Peekable<I>,
get_lo: F1,
get_hi: F2,
get_item_string: F3,
prev_span_end: BytePos,
next_span_start: BytePos,
terminator: &'a str,
}
impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
where I: Iterator<Item = &'a T>,
F1: Fn(&T) -> BytePos,
F2: Fn(&T) -> BytePos,
F3: Fn(&T) -> String
{
type Item = ListItem;
fn next(&mut self) -> Option<Self::Item> {
let white_space: &[_] = &[' ', '\t'];
self.inner.next().map(|item| {
// Pre-comment
let pre_snippet = self.codemap.span_to_snippet(codemap::mk_sp(self.prev_span_end,
(self.get_lo)(item)))
.unwrap();
let pre_snippet = pre_snippet.trim();
let pre_comment = if pre_snippet.len() > 0 {
Some(pre_snippet.to_owned())
} else {
None
};
// Post-comment
let next_start = match self.inner.peek() {
Some(ref next_item) => (self.get_lo)(next_item),
None => self.next_span_start
};
let post_snippet = self.codemap.span_to_snippet(codemap::mk_sp((self.get_hi)(item),
next_start))
.unwrap();
let comment_end = match self.inner.peek() {
Some(..) => {
let block_open_index = post_snippet.find("/*");
let newline_index = post_snippet.find('\n');
let separator_index = post_snippet.find_uncommented(",").unwrap();
match (block_open_index, newline_index) {
// Separator before comment, with the next item on same line.
// Comment belongs to next item.
(Some(i), None) if i > separator_index => {
separator_index + 1
}
// Block-style post-comment before the separator.
(Some(i), None) => {
cmp::max(find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1)
}
// Block-style post-comment. Either before or after the separator.
(Some(i), Some(j)) if i < j => {
cmp::max(find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1)
}
// Potential *single* line comment.
(_, Some(j)) => { j + 1 }
_ => post_snippet.len()
}
},
None => {
post_snippet.find_uncommented(self.terminator)
.unwrap_or(post_snippet.len())
}
};
// Cleanup post-comment: strip separators and whitespace.
self.prev_span_end = (self.get_hi)(item) + BytePos(comment_end as u32);
let mut post_snippet = post_snippet[..comment_end].trim();
if post_snippet.starts_with(',') {
post_snippet = post_snippet[1..].trim_matches(white_space);
} else if post_snippet.ends_with(",") {
post_snippet = post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space);
}
let post_comment = if post_snippet.len() > 0 {
Some(post_snippet.to_owned())
} else {
None
};
ListItem {
pre_comment: pre_comment,
item: (self.get_item_string)(item),
post_comment: post_comment,
}
})
}
}
pub fn itemize_list<'a, 'b, T, I, F1, F2, F3>(codemap: &'a CodeMap,
inner: I,
terminator: &'a str,
get_lo: F1,
get_hi: F2,
get_item_string: F3,
prev_span_end: BytePos,
next_span_start: BytePos)
-> ListItems<'a, I, F1, F2, F3>
where T: 'b,
I: Iterator<Item = &'b T>,
F1: Fn(&T) -> BytePos,
F2: Fn(&T) -> BytePos,
F3: Fn(&T) -> String
{
ListItems {
codemap: codemap,
inner: inner.peekable(),
get_lo: get_lo,
get_hi: get_hi,
get_item_string: get_item_string,
prev_span_end: prev_span_end,
next_span_start: next_span_start,
terminator: terminator,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment