mod namespace;
use crate::markup::{Component, LexOptions, Lexer};
use namespace::NamespaceSink;
use vize_l0::ErrorCode;
use vize_l0::{Allocator, Vec};
use crate::build::build;
use crate::event::{Event, Recorder};
use crate::render::check_fidelity;
use crate::surface::{SurfaceChild, SurfaceTree, Token};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct SurfaceParseOptions {
pub experimental_in_tag_comments: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct SurfaceError {
pub code: ErrorCode,
pub offset: u32,
}
pub fn parse<'a>(
allocator: &'a Allocator,
source: &'a str,
) -> (SurfaceTree<'a>, Vec<'a, SurfaceError>) {
parse_with_options(allocator, source, SurfaceParseOptions::default())
}
pub fn parse_with_options<'a>(
allocator: &'a Allocator,
source: &'a str,
options: SurfaceParseOptions,
) -> (SurfaceTree<'a>, Vec<'a, SurfaceError>) {
let (tree, _, errors) = parse_projection(allocator, source, options, false);
(tree, errors)
}
pub fn parse_with_authored<'a>(
allocator: &'a Allocator,
source: &'a str,
) -> (
SurfaceTree<'a>,
Option<SurfaceTree<'a>>,
Vec<'a, SurfaceError>,
) {
parse_projection(allocator, source, SurfaceParseOptions::default(), true)
}
fn parse_projection<'a>(
allocator: &'a Allocator,
source: &'a str,
options: SurfaceParseOptions,
authored: bool,
) -> (
SurfaceTree<'a>,
Option<SurfaceTree<'a>>,
Vec<'a, SurfaceError>,
) {
construct::<false>(allocator, source, authored, |events, errors| {
let recorder = Recorder { events, errors };
let sink = NamespaceSink::new(allocator, source, recorder);
Lexer::<Component, _>::new(
source,
sink,
LexOptions {
in_tag_comments: options.experimental_in_tag_comments,
..LexOptions::default()
},
)
.run();
})
}
pub(crate) fn construct<'a, const RAW: bool>(
allocator: &'a Allocator,
source: &'a str,
authored: bool,
record: impl FnOnce(&mut Vec<'a, Event>, &mut Vec<'a, SurfaceError>),
) -> (
SurfaceTree<'a>,
Option<SurfaceTree<'a>>,
Vec<'a, SurfaceError>,
) {
construct_with_lint::<RAW, false>(allocator, source, authored, record)
}
pub(crate) fn construct_with_lint<'a, const RAW: bool, const LINT: bool>(
allocator: &'a Allocator,
source: &'a str,
authored: bool,
record: impl FnOnce(&mut Vec<'a, Event>, &mut Vec<'a, SurfaceError>),
) -> (
SurfaceTree<'a>,
Option<SurfaceTree<'a>>,
Vec<'a, SurfaceError>,
) {
let mut events: Vec<'a, Event> = Vec::new_in(&allocator);
let mut errors: Vec<'a, SurfaceError> = Vec::new_in(&allocator);
if u32::try_from(source.len()).is_err() {
let mut children = Vec::new_in(&allocator);
let hole = Token::present(crate::slice::range(source, 0, 0), source);
children.push(SurfaceChild::Unexpected(hole));
return (SurfaceTree { source, children }, None, errors);
}
record(&mut events, &mut errors);
let (tree, repaired) = build::<RAW, LINT>(allocator, source, &events, true);
let authored =
(authored && repaired).then(|| build::<RAW, LINT>(allocator, source, &events, false).0);
debug_assert!(
check_fidelity(&tree).is_ok(),
"L1 fidelity: render(tree) != source"
);
if let Some(authored) = &authored {
debug_assert!(check_fidelity(authored).is_ok(), "authored L1 fidelity");
}
(tree, authored, errors)
}