vize_l2 0.604.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
use super::{Allocator, Kind, check, equal, kind, owner, selected};
use vize_l2::{
    op::Op,
    walk::{NodeEvent, PageWalk, visit_events},
};

#[test]
fn original_nested_html_bodies_complete_in_the_shared_page_order() -> Result<(), &'static str> {
    let arena = Allocator::default();
    let source = "<template><div>a<span>hé<!--kept--></span><br></div>tail</template>";
    let mut original = owner(&arena, source)?;
    {
        let mut walk = original.begin().map_err(|_| "original begin")?;
        let mut children = walk.selected().children();
        equal(
            walk.child(children.next().ok_or("div")?)
                .map_err(|_| "body")?
                .index(),
            0,
        )?;
        equal(
            walk.child(children.next().ok_or("tail")?)
                .map_err(|_| "tail")?
                .index(),
            6,
        )?;
        walk.complete().map_err(|_| "normal root end")?;
    }
    let result = original.finish();
    let view = result.view().map_err(|_| "original complete")?;
    check(core::ptr::eq(view.owner(), &result))?;
    let file = view.file().ok_or("same File")?;
    equal(file.artifact().node_count(), 7)?;
    check(file.is_complete())?;
    check(core::ptr::eq(file.artifact().source(), source))?;
    let [Op::Element(div), Op::Text(tail)] = file.artifact().root().ops.as_slice() else {
        return Err("original root shape");
    };
    equal(div.tag, "div")?;
    check(div.attributes.is_empty() && div.bindings.is_empty())?;
    equal(tail.content, "tail")?;
    let [Op::Text(first), Op::Element(span), Op::Element(br)] = div.children.ops.as_slice() else {
        return Err("actual original siblings");
    };
    equal(first.content, "a")?;
    equal(span.tag, "span")?;
    equal(br.tag, "br")?;
    check(br.children.ops.is_empty())?;
    let [Op::Text(text), Op::Comment(comment)] = span.children.ops.as_slice() else {
        return Err("original inner siblings");
    };
    equal(text.content, "hé")?;
    equal(comment.content, "kept")?;
    let original_div = result
        .selected()
        .children()
        .next()
        .ok_or("selected div")?
        .into_element()
        .ok_or("original Element")?;
    check(core::ptr::eq(original_div.surface().tag(), div.tag))?;
    let mut enters = Vec::new();
    visit_events(
        &mut PageWalk::new(),
        &file.artifact().root().ops,
        &mut |event| {
            if let NodeEvent::Enter {
                id, node, parent, ..
            } = event
            {
                enters.push((id.index(), parent.map(|node| node.index()), node.span()));
            }
        },
    )
    .map_err(|_| "actual traversal")?;
    equal(
        enters.iter().map(|row| (row.0, row.1)).collect::<Vec<_>>(),
        vec![
            (0, None),
            (1, Some(0)),
            (2, Some(0)),
            (3, Some(2)),
            (4, Some(2)),
            (5, Some(0)),
            (6, None),
        ],
    )?;
    for (_, _, span) in enters {
        check(source.get(span.start as usize..span.end as usize).is_some())?;
    }
    Ok(())
}

#[test]
fn original_empty_explicit_self_closing_and_void_html_elements_are_distinct()
-> Result<(), &'static str> {
    let arena = Allocator::default();
    for source in [
        "<template><div/></template>",
        "<template><div></div></template>",
        "<template><input></template>",
    ] {
        let mut original = owner(&arena, source)?;
        {
            let mut walk = original.begin().map_err(|_| "begin")?;
            walk.child(walk.selected().children().next().ok_or("child")?)
                .map_err(|_| "zero-header element")?;
            walk.complete().map_err(|_| "actual end")?;
        }
        let result = original.finish();
        let file = result
            .view()
            .map_err(|_| "complete")?
            .file()
            .ok_or("file")?;
        equal(file.artifact().node_count(), 1)?;
        let [Op::Element(element)] = file.artifact().root().ops.as_slice() else {
            return Err("single original Element");
        };
        check(element.children.ops.is_empty())?;
        equal(
            &source[element.span.start as usize..element.span.end as usize],
            &source["<template>".len()..source.len() - "</template>".len()],
        )?;
    }
    Ok(())
}

#[test]
fn nested_refusal_is_sticky_and_retains_the_actual_constructed_prefix() -> Result<(), &'static str>
{
    let arena = Allocator::default();
    let source = "<template><div>ok<span>bad  text</span></div>tail</template>";
    let mut original = owner(&arena, source)?;
    {
        let mut walk = original.begin().map_err(|_| "begin")?;
        let mut children = walk.selected().children();
        equal(
            kind(walk.child(children.next().ok_or("div")?))?,
            Kind::UnsupportedChild,
        )?;
        equal(
            kind(walk.child(children.next().ok_or("tail")?))?,
            Kind::UnsupportedChild,
        )?;
        equal(kind(walk.complete())?, Kind::UnsupportedChild)?;
    }
    equal(kind(original.begin())?, Kind::Interrupted)?;
    let result = original.finish();
    check(result.view().is_err())?;
    let file = result.file().ok_or("partial File")?;
    check(!file.is_complete())?;
    equal(file.artifact().node_count(), 3)?;
    let [Op::Element(div)] = file.artifact().root().ops.as_slice() else {
        return Err("partial original root");
    };
    let [Op::Text(ok), Op::Element(span)] = div.children.ops.as_slice() else {
        return Err("original completed prefix");
    };
    equal(ok.content, "ok")?;
    check(span.children.ops.is_empty())?;
    equal(result.selected().children().len(), 2)?;
    Ok(())
}

#[test]
fn foreign_reordered_and_nested_children_cannot_stand_in_for_a_root_element()
-> Result<(), &'static str> {
    let arena = Allocator::default();
    let source = "<template><div><span/></div><br/></template>";
    let foreign_source = source.to_owned();
    let foreign = selected(&arena, &foreign_source)?;
    for mode in 0..3 {
        let mut original = owner(&arena, source)?;
        {
            let mut walk = original.begin().map_err(|_| "begin")?;
            let child = match mode {
                0 => foreign.children().next().ok_or("foreign")?,
                1 => walk.selected().children().nth(1).ok_or("reordered")?,
                _ => walk
                    .selected()
                    .children()
                    .next()
                    .ok_or("div")?
                    .into_element()
                    .ok_or("actual div")?
                    .children()
                    .next()
                    .ok_or("span")?,
            };
            equal(kind(walk.child(child))?, Kind::InvalidEvent)?;
            check(walk.complete().is_err())?;
        }
        let result = original.finish();
        check(result.view().is_err())?;
        equal(result.file().ok_or("file")?.artifact().node_count(), 0)?;
    }
    Ok(())
}

#[test]
fn directive_namespace_special_and_operand_routes_remain_unavailable() -> Result<(), &'static str> {
    let arena = Allocator::default();
    for body in [
        "<div :id='x'/>",
        "<div v-pre/>",
        "<div v-if='true'/>",
        "<div>&amp;</div>",
        "<div> </div>",
        "<svg/>",
        "<math/>",
        "<Widget/>",
        "<DIV/>",
        "<template/>",
        "<slot/>",
        "<pre>x</pre>",
        "<textarea>x</textarea>",
        "<title>x</title>",
        "<script>x</script>",
        "<style>x</style>",
    ] {
        let source = format!("<template>{body}</template>");
        let mut original = owner(&arena, &source)?;
        {
            let mut walk = original.begin().map_err(|_| "begin")?;
            let child = walk.selected().children().next().ok_or("original child")?;
            equal(kind(walk.child(child))?, Kind::UnsupportedChild)?;
            check(walk.complete().is_err())?;
        }
        let result = original.finish();
        check(result.view().is_err())?;
        check(!result.file().ok_or("partial file")?.is_complete())?;
    }
    Ok(())
}

#[test]
fn dropping_after_an_original_element_is_not_root_completion() -> Result<(), &'static str> {
    let arena = Allocator::default();
    let mut original = owner(&arena, "<template><div>x</div></template>")?;
    {
        let mut walk = original.begin().map_err(|_| "begin")?;
        walk.child(walk.selected().children().next().ok_or("div")?)
            .map_err(|_| "body")?;
    }
    let result = original.finish();
    check(result.view().is_err())?;
    let file = result.file().ok_or("partial File")?;
    equal(file.artifact().node_count(), 2)?;
    check(!file.is_complete())?;
    check(file.template_interruption().is_some())?;
    Ok(())
}

#[test]
fn forgotten_and_unwound_complete_element_prefixes_cannot_mint_a_view() -> Result<(), &'static str>
{
    let arena = Allocator::default();
    for forgotten in [true, false] {
        let mut original = owner(&arena, "<template><div>x</div></template>")?;
        if forgotten {
            let mut walk = original.begin().map_err(|_| "begin")?;
            walk.child(walk.selected().children().next().ok_or("div")?)
                .map_err(|_| "body")?;
            core::mem::forget(walk);
        } else {
            let interrupted = std::panic::catch_unwind(std::panic::AssertUnwindSafe(
                || -> Result<(), &'static str> {
                    let mut walk = original.begin().map_err(|_| "begin")?;
                    walk.child(walk.selected().children().next().ok_or("div")?)
                        .map_err(|_| "body")?;
                    std::panic::resume_unwind(Box::new(()));
                },
            ));
            check(interrupted.is_err())?;
        }
        equal(kind(original.begin())?, Kind::Interrupted)?;
        let result = original.finish();
        check(result.view().is_err())?;
        let file = result.file().ok_or("same partial File")?;
        equal(file.artifact().node_count(), 2)?;
        check(!file.is_complete())?;
    }
    Ok(())
}