pub fn is_placeholder_start(bytes: &[u8], i: usize) -> bool {
if i == 0 {
return true;
}
!matches!(
bytes[i - 1],
b'0'..=b'9'
| b'A'..=b'Z'
| b'a'..=b'z'
| b'_'
| b'$'
| b'\''
| b'"'
| b'`'
| b'}'
| b']'
)
}
#[inline]
pub fn is_ident_start(b: u8) -> bool {
b.is_ascii_alphabetic() || b == b'_'
}
#[inline]
pub fn is_ident_continue(b: u8) -> bool {
b.is_ascii_alphanumeric() || b == b'_'
}
pub fn scan_line_comment(bytes: &[u8], mut i: usize) -> usize {
while i < bytes.len() && bytes[i] != b'\n' {
i += 1;
}
i
}
pub fn scan_backtick(bytes: &[u8], mut i: usize) -> usize {
i += 1;
while i < bytes.len() {
if bytes[i] == b'`' {
return i + 1;
}
i += 1;
}
i
}
pub fn scan_single_quoted(bytes: &[u8], mut i: usize) -> usize {
i += 1;
while i < bytes.len() {
let sc = bytes[i];
i += 1;
if sc == b'\\' && i < bytes.len() {
i += 1;
} else if sc == b'\'' {
if i < bytes.len() && bytes[i] == b'\'' {
i += 1;
} else {
break;
}
}
}
i
}
#[inline]
fn has_closing_triple(bytes: &[u8], start: usize, triple: &[u8; 3]) -> bool {
start + 2 < bytes.len() && &bytes[start..start + 3] == triple
}
pub fn scan_triple_quoted(bytes: &[u8], mut i: usize, quote: u8) -> usize {
i += 3;
let triple = [quote, quote, quote];
while i < bytes.len() {
if has_closing_triple(bytes, i, &triple) {
return i + 3;
}
i += 1;
}
i
}
pub fn scan_raw_string(bytes: &[u8], mut i: usize, quote: u8) -> usize {
i += 2;
while i < bytes.len() {
if bytes[i] == quote {
return i + 1;
}
i += 1;
}
i
}
pub fn scan_double_quoted(bytes: &[u8], mut i: usize) -> usize {
i += 1;
while i < bytes.len() {
let sc = bytes[i];
i += 1;
if sc == b'\\' && i < bytes.len() {
i += 1;
} else if sc == b'"' {
break;
}
}
i
}
pub fn skip_protected(bytes: &[u8], i: usize) -> Option<usize> {
match bytes[i] {
b'-' if i + 1 < bytes.len() && bytes[i + 1] == b'-' => {
Some(scan_line_comment(bytes, i + 2))
}
b'`' => Some(scan_backtick(bytes, i)),
b'\'' => {
if i + 2 < bytes.len() && bytes[i + 1] == b'\'' && bytes[i + 2] == b'\'' {
Some(scan_triple_quoted(bytes, i, b'\''))
} else {
Some(scan_single_quoted(bytes, i))
}
}
b'"' => {
if i + 2 < bytes.len() && bytes[i + 1] == b'"' && bytes[i + 2] == b'"' {
Some(scan_triple_quoted(bytes, i, b'"'))
} else {
Some(scan_double_quoted(bytes, i))
}
}
b'r' if i + 1 < bytes.len() && (bytes[i + 1] == b'\'' || bytes[i + 1] == b'"') => {
let quote = bytes[i + 1];
if i + 3 < bytes.len() && bytes[i + 2] == quote && bytes[i + 3] == quote {
Some(scan_triple_quoted(bytes, i + 1, quote))
} else {
Some(scan_raw_string(bytes, i, quote))
}
}
_ => None,
}
}
pub fn ident_at(source: &str, start: usize, end: usize) -> &str {
source.get(start..end).unwrap_or("")
}