use vize_l0::SmallVec;
use super::{Lexer, State, types::is_end_of_tag_section};
use crate::markup::profile::Profile;
use crate::markup::token::{LexErrorCode, Sink};
impl<P: Profile, S: Sink> Lexer<'_, P, S> {
pub(super) fn state_in_dir_dynamic_arg(&mut self, _c: u8) {
let (end, closed) = scan_argument(self.input, self.index);
self.index = end;
if closed {
self.sink.on_dir_arg(self.section_start, end);
self.state = State::InDirArg;
self.section_start = end + 1;
} else if end == self.input.len() {
self.index = end.saturating_sub(1);
} else {
self.sink
.on_error(LexErrorCode::MissingDynamicDirectiveArgumentEnd, end);
if self.section_start < end {
self.sink.on_dir_arg(self.section_start, end);
}
self.sink.on_attrib_name_end(end);
self.section_start = end;
self.state = State::AfterAttrName;
if let Some(&c) = self.input.get(end) {
self.state_after_attr_name(c);
}
}
}
}
fn is_boundary(byte: u8) -> bool {
byte == b'=' || is_end_of_tag_section(byte)
}
fn scan_argument(input: &[u8], start: usize) -> (usize, bool) {
let mut delimiters = SmallVec::<[u8; 8]>::new();
delimiters.push(b']');
let mut index = start;
while let Some(&byte) = input.get(index) {
if is_boundary(byte) {
return (index, false);
}
let Some(&delimiter) = delimiters.last() else {
return (index, true);
};
if matches!(delimiter, b'\'' | b'"' | b'`') {
match byte {
b'\\' => {
if input.get(index + 1).is_some_and(|&byte| is_boundary(byte)) {
return (index + 1, false);
}
index += 1;
}
_ if byte == delimiter => {
delimiters.pop();
}
b'$' if delimiter == b'`' && input.get(index + 1) == Some(&b'{') => {
delimiters.push(b'}');
index += 1;
}
_ => {}
}
} else {
match byte {
b'\'' | b'"' | b'`' => delimiters.push(byte),
b'[' => delimiters.push(b']'),
b'(' => delimiters.push(b')'),
b'{' => delimiters.push(b'}'),
b']' | b')' | b'}' if delimiters.last() == Some(&byte) => {
delimiters.pop();
if delimiters.is_empty() {
return (index, true);
}
}
_ => {}
}
}
index += 1;
}
(input.len(), false)
}
#[cfg(test)]
#[expect(clippy::string_slice, reason = "tests assert by panicking")]
mod tests;