use ruff_python_ast::StringFlags;
use crate::string::InterpolatedStringKind;
use super::TokenFlags;
#[derive(Clone, Debug)]
pub(crate) struct InterpolatedStringContext {
flags: TokenFlags,
nesting: u32,
format_spec_depth: u32,
}
impl InterpolatedStringContext {
pub(crate) const fn new(flags: TokenFlags, nesting: u32) -> Option<Self> {
if flags.is_interpolated_string() {
Some(Self {
flags,
nesting,
format_spec_depth: 0,
})
} else {
None
}
}
pub(crate) fn kind(&self) -> InterpolatedStringKind {
if self.flags.is_f_string() {
InterpolatedStringKind::FString
} else if self.flags.is_t_string() {
InterpolatedStringKind::TString
} else {
unreachable!("Can only be constructed when f-string or t-string flag is present")
}
}
pub(crate) const fn flags(&self) -> TokenFlags {
self.flags
}
pub(crate) const fn nesting(&self) -> u32 {
self.nesting
}
pub(crate) fn quote_char(&self) -> char {
self.flags.quote_style().as_char()
}
pub(crate) fn triple_quotes(&self) -> Option<&'static str> {
if self.is_triple_quoted() {
Some(self.flags.quote_str())
} else {
None
}
}
pub(crate) fn is_raw_string(&self) -> bool {
self.flags.is_raw_string()
}
pub(crate) fn is_triple_quoted(&self) -> bool {
self.flags.is_triple_quoted()
}
const fn open_parentheses_count(&self, current_nesting: u32) -> u32 {
current_nesting.saturating_sub(self.nesting)
}
pub(crate) const fn is_in_interpolation(&self, current_nesting: u32) -> bool {
self.open_parentheses_count(current_nesting) > self.format_spec_depth
}
pub(crate) const fn is_in_format_spec(&self, current_nesting: u32) -> bool {
self.format_spec_depth > 0 && !self.is_in_interpolation(current_nesting)
}
pub(crate) fn try_start_format_spec(&mut self, current_nesting: u32) -> bool {
if self
.open_parentheses_count(current_nesting)
.saturating_sub(self.format_spec_depth)
== 1
{
self.format_spec_depth += 1;
true
} else {
false
}
}
pub(crate) fn try_end_format_spec(&mut self, current_nesting: u32) {
if self.is_in_format_spec(current_nesting) {
self.format_spec_depth = self.format_spec_depth.saturating_sub(1);
}
}
}
#[derive(Debug, Default)]
pub(crate) struct InterpolatedStrings {
stack: Vec<InterpolatedStringContext>,
}
impl InterpolatedStrings {
pub(crate) fn push(&mut self, context: InterpolatedStringContext) {
self.stack.push(context);
}
pub(crate) fn pop(&mut self) -> Option<InterpolatedStringContext> {
self.stack.pop()
}
pub(crate) fn current(&self) -> Option<&InterpolatedStringContext> {
self.stack.last()
}
pub(crate) fn current_mut(&mut self) -> Option<&mut InterpolatedStringContext> {
self.stack.last_mut()
}
pub(crate) fn checkpoint(&self) -> InterpolatedStringsCheckpoint {
InterpolatedStringsCheckpoint(self.stack.clone())
}
pub(crate) fn rewind(&mut self, checkpoint: InterpolatedStringsCheckpoint) {
self.stack = checkpoint.0;
}
}
#[derive(Debug, Clone)]
pub(crate) struct InterpolatedStringsCheckpoint(Vec<InterpolatedStringContext>);