mod native;
#[cfg(test)]
mod tests;
use crate::markup::lex::compat::Callbacks;
use crate::markup::token::QuoteType;
use vize_l0::ErrorCode;
use vize_l0::Vec;
use crate::markup::parse::SurfaceError;
use crate::markup::surface::{LintHeaderFact, LintTagFact};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum EventKind {
Text,
Interpolation,
OpenTagName,
OpenTagEnd,
SelfClosingTag,
CloseTag,
AttrName,
AttrNameEnd,
AttrData,
AttrEnd,
Comment,
Cdata,
ProcessingInstruction,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Event {
pub kind: EventKind,
pub aux: u8,
pub start: u32,
pub end: u32,
}
impl Event {
fn new(kind: EventKind, start: usize, end: usize) -> Self {
Self {
kind,
aux: 0,
start: start as u32,
end: end as u32,
}
}
pub(crate) fn quote(&self) -> QuoteType {
debug_assert!(self.kind == EventKind::AttrEnd);
match self.aux {
1 => QuoteType::Unquoted,
2 => QuoteType::Single,
3 => QuoteType::Double,
_ => QuoteType::NoValue,
}
}
pub(crate) fn is_verbatim_opening(&self) -> bool {
debug_assert!(matches!(
self.kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.aux & 1 != 0
}
pub(crate) fn lint_tag(&self) -> Option<LintTagFact> {
debug_assert!(matches!(
self.kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
LintTagFact::from_aux(self.aux)
}
pub(crate) fn lint_header_is_literal(&self) -> bool {
debug_assert!(matches!(
self.kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.aux & 16 != 0
}
pub(crate) fn lint_in_table_context(&self) -> bool {
debug_assert!(matches!(
self.kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.aux & 32 != 0
}
pub(crate) fn lint_in_recovery_context(&self) -> bool {
debug_assert!(matches!(
self.kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.aux & 64 != 0
}
pub(crate) fn interpolation_width(&self) -> usize {
debug_assert!(self.kind == EventKind::Interpolation);
if self.aux == 3 { 3 } else { 2 }
}
}
pub(crate) struct Recorder<'a, 'v> {
pub events: &'v mut Vec<'a, Event>,
pub errors: &'v mut Vec<'a, SurfaceError>,
}
impl Recorder<'_, '_> {
fn push(&mut self, kind: EventKind, start: usize, end: usize) {
self.events.push(Event::new(kind, start, end));
}
pub(crate) fn raw_interpolation(&mut self, start: usize, end: usize) {
self.events.push(Event {
kind: EventKind::Interpolation,
aux: 3,
start: start as u32,
end: end as u32,
});
}
fn attr_end(&mut self, quote: QuoteType, end: usize) {
self.events.push(Event {
kind: EventKind::AttrEnd,
aux: quote as u8,
start: end as u32,
end: end as u32,
});
}
pub(crate) fn opening_end(&mut self, kind: EventKind, end: usize, verbatim: bool) {
debug_assert!(matches!(
kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.events.push(Event {
kind,
aux: u8::from(verbatim),
start: end as u32,
end: end as u32,
});
}
pub(crate) fn opening_end_with_lint(
&mut self,
kind: EventKind,
end: usize,
verbatim: bool,
facts: LintHeaderFact,
) {
debug_assert!(matches!(
kind,
EventKind::OpenTagEnd | EventKind::SelfClosingTag
));
self.events.push(Event {
kind,
aux: u8::from(verbatim)
| facts.kind.map_or(0, |fact| (fact as u8) << 1)
| (u8::from(facts.literal) << 4)
| (u8::from(facts.table_context) << 5)
| (u8::from(facts.recovery_context) << 6),
start: end as u32,
end: end as u32,
});
}
}
impl Callbacks for Recorder<'_, '_> {
fn on_text(&mut self, start: usize, end: usize) {
self.push(EventKind::Text, start, end);
}
fn on_text_entity(&mut self, _char: char, start: usize, end: usize) {
self.push(EventKind::Text, start, end);
}
fn on_interpolation(&mut self, start: usize, end: usize) {
self.push(EventKind::Interpolation, start, end);
}
fn on_open_tag_name(&mut self, start: usize, end: usize) {
self.push(EventKind::OpenTagName, start, end);
}
fn on_open_tag_end(&mut self, end: usize) {
self.push(EventKind::OpenTagEnd, end, end);
}
fn on_self_closing_tag(&mut self, end: usize) {
self.push(EventKind::SelfClosingTag, end, end);
}
fn on_close_tag(&mut self, start: usize, end: usize) {
self.push(EventKind::CloseTag, start, end);
}
fn on_attrib_data(&mut self, start: usize, end: usize) {
self.push(EventKind::AttrData, start, end);
}
fn on_attrib_entity(&mut self, _char: char, start: usize, end: usize) {
self.push(EventKind::AttrData, start, end);
}
fn on_attrib_end(&mut self, quote: QuoteType, end: usize) {
self.attr_end(quote, end);
}
fn on_attrib_name(&mut self, start: usize, end: usize) {
self.push(EventKind::AttrName, start, end);
}
fn on_attrib_name_end(&mut self, end: usize) {
self.push(EventKind::AttrNameEnd, end, end);
}
fn on_dir_name(&mut self, start: usize, end: usize) {
self.push(EventKind::AttrName, start, end);
}
fn on_dir_arg(&mut self, start: usize, end: usize) {
self.push(EventKind::AttrName, start, end);
}
fn on_dir_modifier(&mut self, start: usize, end: usize) {
self.push(EventKind::AttrName, start, end);
}
fn on_comment(&mut self, start: usize, end: usize) {
self.push(EventKind::Comment, start, end);
}
fn on_cdata(&mut self, start: usize, end: usize) {
self.push(EventKind::Cdata, start, end);
}
fn on_processing_instruction(&mut self, start: usize, end: usize) {
self.push(EventKind::ProcessingInstruction, start, end);
}
fn on_end(&mut self) {}
fn on_error(&mut self, code: ErrorCode, index: usize) {
self.errors.push(SurfaceError {
code,
offset: index as u32,
});
}
}