Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sway-fmt-v2/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub(crate) mod attribute;
pub(crate) mod bracket;
pub(crate) mod comments;
pub(crate) mod generics;
pub(crate) mod indent_style;
pub(crate) mod item;
Expand Down
78 changes: 78 additions & 0 deletions sway-fmt-v2/src/utils/comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use anyhow::Result;
use std::{cmp::Ordering, collections::BTreeMap, sync::Arc};
use sway_parse::token::{lex_commented, Comment, CommentedTokenTree};

/// Represents a span for the comments in a spesific file
/// A stripped down version of sway-types::src::Span
#[derive(PartialEq, Eq, Debug)]
pub struct CommentSpan {
// The byte position in the string of the start of the span.
start: usize,
// The byte position in the string of the end of the span.
end: usize,
}

impl Ord for CommentSpan {
fn cmp(&self, other: &Self) -> Ordering {
self.start.cmp(&other.start)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it comes to ordering spans, I think the correct approach might be to reflect not just the order in which the start occurs, but also the order in which the spans would be visited during traversal (e.g. larger enclosing spans preceding inner spans.)

E.g. when comparing the spans 2..6 and 2..4, the 2..6 span should come first as it encloses the 2..4 span. I think this would look something like:

match self.start.cmp(&other.start) {
    Ordering::Equal => other.end.cmp(&self.end),
    ord => ord,
}

Anyway, this is more relevant to the ordering of AST spans generally, and shouldn't be relevant to our case as I suppose comments cannot overlap 😂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually thinking about this while writing that part but later on couldn't think of an example where comments would be overlapping as you pointed out 😄. But I will fix the ordering like this. Although it seems like overlapping won't be happening, if somehow it happens I feel like this will be really hard to debug.

}
}

impl PartialOrd for CommentSpan {
fn partial_cmp(&self, other: &CommentSpan) -> Option<Ordering> {
Some(self.cmp(other))
}
}

pub type CommentMap = BTreeMap<CommentSpan, Comment>;

/// Get the CommentedTokenStream and collect the spans -> Comment mapping for the input source
/// code.
pub fn construct_comment_map(input: Arc<str>) -> Result<CommentMap> {
let mut comment_map = BTreeMap::new();

// pass the input through lexer
let commented_token_stream = lex_commented(&input, 0, input.len(), None)?;
let tts = commented_token_stream.token_trees().iter();

for comment in tts {
if let CommentedTokenTree::Comment(comment) = comment {
let comment_span = CommentSpan {
start: comment.span.start(),
end: comment.span.end(),
};
comment_map.insert(comment_span, comment.clone());
}
// TODO: implement CommentedTokenTree::Tree case for getting the comments inside code
// blocks
}
Ok(comment_map)
}

#[cfg(test)]
mod tests {
use super::{construct_comment_map, CommentSpan};
use std::{ops::Bound::Included, sync::Arc};

#[test]
fn test_comment_span_map() {
let input = r#"
// Single-line comment.
struct Foo {
/* multi-
* line-
* comment */
bar: i32,
}
"#;
let map = construct_comment_map(Arc::from(input)).unwrap();
assert!(map.len() != 0);
let range_start_span = CommentSpan { start: 0, end: 32 };
let range_end_span = CommentSpan { start: 33, end: 34 };
let found_comment = map
.range((Included(range_start_span), Included(range_end_span)))
.last()
.unwrap();
assert_eq!(found_comment.1.span.as_str(), "// Single-line comment.");
}
}