use crate::js::chars::{is_space, space_run, unit, unit_at};
#[derive(Clone, Debug, Default)]
pub(crate) struct JisonTokens {
pub(crate) types: Vec<usize>,
pub(crate) texts: Vec<String>,
pub(crate) starts: Vec<usize>,
}
impl JisonTokens {
pub(crate) fn emit(&mut self, kind: usize, src: &str, start: usize, end: usize) {
self.types.push(kind);
self.texts.push(src[start..end].to_string());
self.starts.push(start);
}
}
pub(crate) fn line_end(src: &str, from: usize) -> usize {
match src.as_bytes()[from..].iter().position(|&b| b == b'\n') {
Some(at) => from + at,
None => src.len(),
}
}
pub(crate) fn keyword_at(src: &str, p: usize, word: &str) -> bool {
let Some(at) = src.as_bytes().get(p..p + word.len()) else {
return false;
};
at.iter().zip(word.bytes()).all(|(&c, w)| c | 32 == w)
}
pub(crate) fn skip_trivia(src: &str, from: usize) -> usize {
let n = src.len();
let mut p = from;
while p < n {
let (c, size) = unit_at(src, p);
if c == 37 && unit(src, p + 1) != 123 {
p = line_end(src, p);
} else if c == 10 {
return p;
} else if is_space(c) {
p = space_run(src, p + size);
} else if c == 35 {
p = line_end(src, p);
} else {
return p;
}
}
p
}
pub(crate) fn accessibility(src: &str, p: usize, out: &mut JisonTokens, first: usize) -> usize {
let descr = keyword_at(src, p, "accdescr");
if !descr && !keyword_at(src, p, "acctitle") {
return p;
}
let n = src.len();
let mut q = space_run(src, p + 8);
let c = unit(src, q);
if c == 58 {
q = space_run(src, q + 1);
let end = line_end(src, q);
let kind = if descr { first + 2 } else { first };
out.emit(kind, src, p, q);
out.emit(kind + 1, src, q, end);
return end;
}
if !descr || c != 123 {
return p;
}
q = space_run(src, q + 1);
while unit(src, q) != 125 {
let end = match src.as_bytes()[q..].iter().position(|&b| b == b'}') {
Some(at) => q + at,
None => n,
};
out.emit(first + 4, src, q, end);
if q == n {
return n;
}
q = end;
}
q + 1
}