use vize_armature::tokenizer::Tokenizer;
use vize_l0::{Allocator, Vec};
use vize_relief::ErrorCode;
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>,
) {
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);
}
{
let recorder = Recorder {
events: &mut events,
errors: &mut errors,
};
let mut tokenizer = Tokenizer::new(source, recorder);
tokenizer.set_in_tag_comments(options.experimental_in_tag_comments);
tokenizer.tokenize();
}
let (tree, repaired) = build(allocator, source, &events, true);
let authored = (authored && repaired).then(|| build(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)
}