vize_l2 0.580.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
use super::prepare::children;
use crate::{
    artifact::{ArtifactError, RegionBuilder},
    lang::js::jsx_body::records::Record,
    op::{Attribute, Namespace},
    resolution::SyntaxKind as Syntax,
};
use vize_l0::Vec;

pub(super) fn element<'a>(
    records: &[Record<'a>],
    index: usize,
    region: &mut RegionBuilder<'_, 'a>,
) -> Result<(), ArtifactError> {
    let row = records.get(index).ok_or_else(invalid)?;
    let mut body = children(records, index);
    let opening = body.next().ok_or_else(invalid)?;
    let mut header = children(records, opening);
    let name = records
        .get(header.next().ok_or_else(invalid)?)
        .ok_or_else(invalid)?;
    let Syntax::Intrinsic(tag) = name.kind else {
        return Err(invalid());
    };
    let mut attributes = Vec::new_in(&region.allocator());
    for attribute in header {
        let row = records.get(attribute).ok_or_else(invalid)?;
        let Syntax::Attribute(name) = row.kind else {
            return Err(invalid());
        };
        let value = children(records, attribute)
            .nth(1)
            .and_then(|index| records.get(index))
            .and_then(|row| match row.kind {
                Syntax::AttributeString(value) => Some(value),
                _ => None,
            });
        attributes.push(Attribute {
            name,
            value,
            span: row.span,
        });
    }
    let mut error = None;
    region.element(tag, Namespace::Html, attributes, row.span, |region, _| {
        for child in body {
            if error.is_some() {
                break;
            }
            error = self::child(records, child, region).err();
        }
    })?;
    error.map_or(Ok(()), Err)
}

pub(super) fn node<'a>(
    records: &[Record<'a>],
    index: usize,
    region: &mut RegionBuilder<'_, 'a>,
) -> Result<(), ArtifactError> {
    match records.get(index).ok_or_else(invalid)?.kind {
        Syntax::Element => element(records, index, region),
        Syntax::Fragment => {
            for index in children(records, index) {
                child(records, index, region)?;
            }
            Ok(())
        }
        _ => Err(invalid()),
    }
}

fn child<'a>(
    records: &[Record<'a>],
    index: usize,
    region: &mut RegionBuilder<'_, 'a>,
) -> Result<(), ArtifactError> {
    let row = records.get(index).ok_or_else(invalid)?;
    match row.kind {
        Syntax::Element | Syntax::Fragment => node(records, index, region),
        Syntax::Text(text) if super::whitespace::ignored(text) => Ok(()),
        Syntax::Text(text) => region.text(text, row.span).map(|_| ()),
        // Boundary records stay with the actual original owner. Backend anchor
        // realization is not a generic semantic text node or HTML element.
        Syntax::Container | Syntax::Closing | Syntax::FragmentOpening | Syntax::FragmentClosing => {
            Ok(())
        }
        _ => Err(invalid()),
    }
}

fn invalid() -> ArtifactError {
    ArtifactError::InvalidSpan {
        node: None,
        span: vize_l0::Span::new(0, 0),
    }
}