use super::super::lexeme::LexemeKind;
const INLINE: LexemeKind = LexemeKind::CommentInline;
const MULTILINE: LexemeKind = LexemeKind::CommentMultiline;
const UNDETECTED: (LexemeKind, usize) = (LexemeKind::Undetected, 0);
pub fn detect_comment(
orig: &str,
chr: usize,
) -> (
LexemeKind,
usize,
) {
let len = orig.len();
if len < chr + 2 { return UNDETECTED }
if get_aot(orig, chr) != "/" { return UNDETECTED }
match get_aot(orig, chr+1) {
"/" => detect_inline_comment(orig, chr, len),
"*" => detect_multiline_comment(orig, chr, len),
_ => UNDETECTED,
}
}
fn get_aot(orig: &str, c: usize) -> &str { orig.get(c..c+1).unwrap_or("~") }
fn detect_inline_comment(
orig: &str,
chr: usize,
len: usize,
) -> (
LexemeKind,
usize,
) {
let mut i = chr + 2;
while i < len - 1 {
let mut j = i + 1;
while !orig.is_char_boundary(j) { j += 1 }
if &orig[i..j] == "\n" { return (INLINE, i)
}
i = j;
}
(INLINE, len)
}
fn detect_multiline_comment(
orig: &str,
chr: usize,
len: usize,
) -> (
LexemeKind,
usize,
) {
let mut depth = 0;
let mut i = chr + 2;
while i < len {
let mut j = i + 1;
while !orig.is_char_boundary(j) { j += 1 }
let c0 = &orig[i..j];
let c1 = get_aot(orig, j);
if c0 == "*" && c1 == "/" {
if depth == 0 {
return (MULTILINE, i + 2)
} else {
depth -= 1;
j += 1;
}
} else if c0 == "/" && c1 == "*" {
depth += 1;
j += 1;
}
i = j;
}
UNDETECTED
}
#[cfg(test)]
mod tests {
use super::detect_comment as detect;
use super::INLINE as I;
use super::MULTILINE as M;
use super::UNDETECTED as U;
#[test]
fn detect_comment_inline() {
let orig = "abc//ok\nxyz";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), (I,7)); assert_eq!(detect(orig, 4), U); let orig = "abc//okxyz";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), (I,10)); assert_eq!(detect(orig, 4), U); let orig = "abc//ok\r\nxyz";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), (I,8)); assert_eq!(detect(orig, 4), U); let orig = "//";
assert_eq!(detect(orig, 0), (I,2)); assert_eq!(detect(orig, 1), U); let orig = "//\n";
assert_eq!(detect(orig, 0), (I,3)); assert_eq!(detect(orig, 1), U); assert_eq!(detect("//€", 0), (I,5)); assert_eq!(detect("//abc€", 0), (I,8)); }
#[test]
fn detect_comment_multiline_basic() {
let orig = "abc/*ok\n*/z";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), (M,10)); assert_eq!(detect(orig, 4), U); assert_eq!(detect("/** Here's a doc */", 0), (M,19));
assert_eq!(detect("/**A/*A*/*/", 0), (M,11));
assert_eq!(detect("/**A/*A'*/*/", 0), (M,12));
let orig = "abc/*ok*/";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), (M,9)); assert_eq!(detect(orig, 4), U); let orig = "/**/";
assert_eq!(detect(orig, 0), (M,4)); assert_eq!(detect(orig, 1), U); let orig = "abc/*nope*";
assert_eq!(detect(orig, 2), U); assert_eq!(detect(orig, 3), U); assert_eq!(detect(orig, 4), U); }
#[test]
fn detect_comment_multiline_nested() {
let orig = "/* outer /* inner */ outer */";
assert_eq!(detect(orig, 0), (M,29)); assert_eq!(detect(orig, 9), (M,20)); let orig = "pre-/* 0 /* 1 */ 0 /* 2 /* 3 */ 2 */ 0 */-post";
assert_eq!(detect(orig, 3), U); assert_eq!(detect(orig, 4), (M,41)); assert_eq!(detect(orig, 5), U); assert_eq!(detect(orig, 9), (M,16)); assert_eq!(detect(orig, 19),(M,36)); let orig = "/*/*/ */ */";
assert_eq!(detect(orig, 0), (M,11)); assert_eq!(detect(orig, 1), U); assert_eq!(detect(orig, 2), (M,8)); let orig = "/*/* */* */";
assert_eq!(detect(orig, 0), (M,11)); assert_eq!(detect(orig, 1), U); assert_eq!(detect(orig, 2), (M,7)); let orig = "/* outer /* inner */ missing trailing slash *";
assert_eq!(detect(orig, 0), U);
}
#[test]
fn detect_comment_will_not_panic() {
assert_eq!(detect("", 0), U); assert_eq!(detect("/", 0), U); assert_eq!(detect("xyz/", 3), U); assert_eq!(detect("*", 0), U); assert_eq!(detect("//", 0), (I,2)); assert_eq!(detect("//\n", 0), (I,3)); assert_eq!(detect("//abc", 0), (I,5)); assert_eq!(detect("//abc\n", 0), (I,6)); assert_eq!(detect("/*", 0), U); assert_eq!(detect("*/", 0), U); assert_eq!(detect("/**/", 0), (M,4)); assert_eq!(detect("/*abc", 0), U); assert_eq!(detect("/*abc*", 0), U); assert_eq!(detect("/*abc*/", 0), (M,7)); assert_eq!(detect("/*abc*/\n", 0), (M,7)); assert_eq!(detect("/*abc\n*/", 0), (M,8)); assert_eq!(detect("abc", 2), U); assert_eq!(detect("abc", 3), U); assert_eq!(detect("abc", 4), U); assert_eq!(detect("abc", 100), U); assert_eq!(detect("€", 1), U); assert_eq!(detect("/€", 0), U); assert_eq!(detect("/*€", 0), U); }
}