#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum RustBraceScanState {
Normal,
LineComment,
BlockComment,
StringLit { escape: bool },
CharLit { escape: bool },
RawString { hash_count: usize },
}
pub(super) fn rust_brace_try_leave_normal_for_literal(
chars: &[char],
pos: usize,
) -> Option<(RustBraceScanState, usize)> {
let ch = *chars.get(pos)?;
if ch == '/' && pos + 1 < chars.len() && chars[pos + 1] == '/' {
return Some((RustBraceScanState::LineComment, pos + 2));
}
if ch == '/' && pos + 1 < chars.len() && chars[pos + 1] == '*' {
return Some((RustBraceScanState::BlockComment, pos + 2));
}
if ch == 'r' || ch == 'R' {
if pos + 1 < chars.len() && chars[pos + 1] == '"' {
return Some((RustBraceScanState::RawString { hash_count: 0 }, pos + 2));
}
if pos + 1 < chars.len() && chars[pos + 1] == '#' {
let mut hash_count = 0usize;
let mut j = pos + 1;
while j < chars.len() && chars[j] == '#' {
hash_count += 1;
j += 1;
}
if j < chars.len() && chars[j] == '"' {
return Some((RustBraceScanState::RawString { hash_count }, j + 1));
}
}
}
if ch == '"' {
return Some((RustBraceScanState::StringLit { escape: false }, pos + 1));
}
if ch == '\'' {
return Some((RustBraceScanState::CharLit { escape: false }, pos + 1));
}
None
}
pub(super) fn rust_brace_stack_on_normal_char(
ch: char,
started: &mut bool,
brace_count: &mut i32,
line_idx: usize,
end_line: &mut Option<usize>,
) -> bool {
if !*started {
if ch == '{' {
*started = true;
*brace_count = 1;
}
false
} else if ch == '{' {
*brace_count += 1;
false
} else if ch == '}' {
*brace_count -= 1;
if *brace_count == 0 {
*end_line = Some(line_idx);
true
} else {
false
}
} else {
false
}
}
pub(super) struct RustBraceScanCtx<'a> {
pub line_idx: usize,
pub chars: &'a [char],
pub started: &'a mut bool,
pub brace_count: &'a mut i32,
pub end_line: &'a mut Option<usize>,
}
pub(super) enum RustBraceLineStep {
Continue {
state: RustBraceScanState,
pos: usize,
},
BreakCharLoop,
BreakLineScan,
}
pub(super) fn rust_brace_scan_step(
state: RustBraceScanState,
pos: usize,
ch: char,
ctx: &mut RustBraceScanCtx<'_>,
) -> RustBraceLineStep {
match state {
RustBraceScanState::Normal => rust_brace_step_normal(pos, ch, ctx),
RustBraceScanState::LineComment => RustBraceLineStep::BreakLineScan,
RustBraceScanState::BlockComment => rust_brace_step_block_comment(pos, ch, ctx.chars),
RustBraceScanState::StringLit { escape } => rust_brace_step_string_lit(escape, pos, ch),
RustBraceScanState::CharLit { escape } => rust_brace_step_char_lit(escape, pos, ch),
RustBraceScanState::RawString { hash_count } => {
rust_brace_step_raw_string(hash_count, pos, ch, ctx.chars)
}
}
}
fn rust_brace_step_normal(
pos: usize,
ch: char,
ctx: &mut RustBraceScanCtx<'_>,
) -> RustBraceLineStep {
if let Some((next, np)) = rust_brace_try_leave_normal_for_literal(ctx.chars, pos) {
return RustBraceLineStep::Continue {
state: next,
pos: np,
};
}
if rust_brace_stack_on_normal_char(ch, ctx.started, ctx.brace_count, ctx.line_idx, ctx.end_line)
{
return RustBraceLineStep::BreakCharLoop;
}
RustBraceLineStep::Continue {
state: RustBraceScanState::Normal,
pos: pos + 1,
}
}
fn rust_brace_step_block_comment(pos: usize, ch: char, chars: &[char]) -> RustBraceLineStep {
if ch == '*' && pos + 1 < chars.len() && chars[pos + 1] == '/' {
RustBraceLineStep::Continue {
state: RustBraceScanState::Normal,
pos: pos + 2,
}
} else {
RustBraceLineStep::Continue {
state: RustBraceScanState::BlockComment,
pos: pos + 1,
}
}
}
fn rust_brace_step_string_lit(escape: bool, pos: usize, ch: char) -> RustBraceLineStep {
if escape {
return RustBraceLineStep::Continue {
state: RustBraceScanState::StringLit { escape: false },
pos: pos + 1,
};
}
if ch == '\\' {
return RustBraceLineStep::Continue {
state: RustBraceScanState::StringLit { escape: true },
pos: pos + 1,
};
}
if ch == '"' {
return RustBraceLineStep::Continue {
state: RustBraceScanState::Normal,
pos: pos + 1,
};
}
RustBraceLineStep::Continue {
state: RustBraceScanState::StringLit { escape: false },
pos: pos + 1,
}
}
fn rust_brace_step_char_lit(escape: bool, pos: usize, ch: char) -> RustBraceLineStep {
if escape {
return RustBraceLineStep::Continue {
state: RustBraceScanState::CharLit { escape: false },
pos: pos + 1,
};
}
if ch == '\\' {
return RustBraceLineStep::Continue {
state: RustBraceScanState::CharLit { escape: true },
pos: pos + 1,
};
}
if ch == '\'' {
return RustBraceLineStep::Continue {
state: RustBraceScanState::Normal,
pos: pos + 1,
};
}
RustBraceLineStep::Continue {
state: RustBraceScanState::CharLit { escape: false },
pos: pos + 1,
}
}
fn rust_brace_step_raw_string(
hash_count: usize,
pos: usize,
ch: char,
chars: &[char],
) -> RustBraceLineStep {
if ch == '"' {
let mut ok = true;
for k in 0..hash_count {
if pos + 1 + k >= chars.len() || chars[pos + 1 + k] != '#' {
ok = false;
break;
}
}
if ok {
return RustBraceLineStep::Continue {
state: RustBraceScanState::Normal,
pos: pos + 1 + hash_count,
};
}
}
RustBraceLineStep::Continue {
state: RustBraceScanState::RawString { hash_count },
pos: pos + 1,
}
}