vize_l2 0.485.0

L2 - the Davinci semantic IR (codename Disegno): the neutral op family every input dialect lowers into
Documentation
#![expect(
    clippy::panic_in_result_fn,
    reason = "assertions verify original-owner completion and unwind laws"
)]

use super::*;
extern crate std;
use crate::file::ScriptUnit;
use crate::lang::js::file::observer::{
    CallEvent, DeclaredEvent, FileObserver, StatementEvent, SyntaxEvent,
};
use crate::resolution::{ResolutionErrorKind, SyntaxEdge, SyntaxKind};
use oxc_parser::Parser;
use oxc_span::SourceType;
use vize_l0::SourceRoot;

type LawResult = Result<(), &'static str>;

struct Interrupt<'r, 'a> {
    recorder: &'r mut Recorder<'a>,
}
impl<'a> FileObserver<'a> for Interrupt<'_, 'a> {
    type Checkpoint = <Recorder<'a> as FileObserver<'a>>::Checkpoint;
    fn unit(&mut self, _: &ScriptUnit) {}
    fn statement(&mut self, _: StatementEvent<'_, 'a>) {}
    fn declared(&mut self, _: DeclaredEvent<'_, 'a>) {}
    fn checkpoint(&self) -> Self::Checkpoint {
        self.recorder.checkpoint()
    }
    fn call(&mut self, _: CallEvent<'_, 'a>) -> Result<(), ResolutionErrorKind> {
        Ok(())
    }
    fn syntax(&mut self, event: SyntaxEvent<'a>) -> Result<(), ResolutionErrorKind> {
        let interrupt =
            matches!(event.kind, SyntaxKind::Component(_)) && event.edge == SyntaxEdge::Leave;
        self.recorder.syntax(event)?;
        if interrupt {
            panic!("original syntax callback interrupted");
        }
        Ok(())
    }
    fn rollback(&mut self, checkpoint: Self::Checkpoint) {
        self.recorder.rollback(checkpoint);
    }
}

#[test]
fn caught_unwind_preserves_original_comments_partial_records_and_real_file_interruption()
-> LawResult {
    let arena = Allocator::default();
    let source = "/*kept*/ import C from 'dep'; const view = <C/>;";
    let block = SourceRoot::new(source).map_err(|_| "source")?.whole_block();
    let original = Parser::new(&arena, source, SourceType::jsx()).parse_observed();
    let body_ptr = original
        .admitted()
        .ok_or("admission")?
        .program()
        .body
        .as_ptr();
    let mut producer = JsxFileProducer::new(&arena, original, block, 0).map_err(|_| "producer")?;
    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
        producer.walk_with(|file, input, recorder| {
            file.program_observed(input, ProgramScope::Module, &mut Interrupt { recorder })
                .map(|_| ())
        })
    }));
    assert!(result.is_err());
    assert_eq!(producer.walk(), Err(JsxFileError::AlreadyWalked));
    let rejected = match producer.finish() {
        Err(rejected) => rejected,
        Ok(_) => return Err("interrupted seal"),
    };
    assert_eq!(rejected.error(), JsxFileError::Interrupted);
    assert_eq!(
        rejected
            .observation()
            .admitted()
            .ok_or("original")?
            .program()
            .body
            .as_ptr(),
        body_ptr
    );
    assert_eq!(rejected.observation().comments().len(), 1);
    assert_eq!(rejected.recorded_nodes(), 4);
    let file = rejected.file().ok_or("partial file")?;
    assert!(!file.is_complete());
    assert_eq!(file.interrupted_programs().count(), 1);
    assert_eq!(file.references().len(), 1);
    Ok(())
}

struct Damage<'r, 'a> {
    recorder: &'r mut Recorder<'a>,
}
impl<'a> FileObserver<'a> for Damage<'_, 'a> {
    type Checkpoint = <Recorder<'a> as FileObserver<'a>>::Checkpoint;
    fn unit(&mut self, _: &ScriptUnit) {}
    fn statement(&mut self, _: StatementEvent<'_, 'a>) {}
    fn declared(&mut self, _: DeclaredEvent<'_, 'a>) {}
    fn checkpoint(&self) -> Self::Checkpoint {
        self.recorder.checkpoint()
    }
    fn call(&mut self, _: CallEvent<'_, 'a>) -> Result<(), ResolutionErrorKind> {
        Ok(())
    }
    fn syntax(&mut self, mut event: SyntaxEvent<'a>) -> Result<(), ResolutionErrorKind> {
        if event.kind == SyntaxKind::Element && event.edge == SyntaxEdge::Leave {
            event.span.end -= 1;
        }
        self.recorder.syntax(event)
    }
    fn rollback(&mut self, checkpoint: Self::Checkpoint) {
        self.recorder.rollback(checkpoint);
    }
}

#[test]
fn late_unbalanced_header_rolls_back_actual_expression_and_cannot_seal() -> LawResult {
    let arena = Allocator::default();
    let source = "import C from 'dep'; const view = <C></C>;";
    let block = SourceRoot::new(source).map_err(|_| "source")?.whole_block();
    let mut producer = JsxFileProducer::new(
        &arena,
        Parser::new(&arena, source, SourceType::jsx()).parse_observed(),
        block,
        0,
    )
    .map_err(|_| "producer")?;
    producer
        .walk_with(|file, input, recorder| {
            file.program_observed(input, ProgramScope::Module, &mut Damage { recorder })
                .map(|_| ())
        })
        .map_err(|_| "walk")?;
    let rejected = match producer.finish() {
        Err(rejected) => rejected,
        Ok(_) => return Err("damaged seal"),
    };
    assert_eq!(rejected.error(), JsxFileError::IncompleteFile);
    assert_eq!(rejected.recorded_nodes(), 0);
    let file = rejected.file().ok_or("file")?;
    assert_eq!(file.references().len(), 0);
    assert_eq!(file.issues().len(), 1);
    assert_eq!(
        file.issues().first().ok_or("issue")?.kind,
        crate::file::FileIssueKind::InvalidSpan
    );
    Ok(())
}