vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Rust code writer.

use std::fs;
use std::path::{Path, PathBuf};

use crate::generate::emit::independence::{verify_test_independence, CertificateVerdict};
use crate::generate::emit::GenError;

/// Rendered Rust test ready for syntax validation and disk emission.
pub struct EmittedTest<'a> {
    /// Function name.
    pub test_name: &'a str,
    /// Provenance header.
    pub provenance: &'a str,
    /// Rendered template context stored as comments.
    pub rendered_template: &'a str,
    /// Rust function body, including `#[test]`.
    pub rust: &'a str,
    /// Op id under test — used by the independence certificate to detect
    /// tests that would derive their expected value from the op they are
    /// testing.
    pub op_under_test: &'a str,
}

/// Validate the rendered Rust, run the independence certificate, and
/// write it to `path` iff both gates pass.
///
/// The independence certificate is the single most important gate between
/// a generated test and disk: a tautological test (one that computes its
/// expected value by invoking the code it is testing) proves nothing. If
/// the certificate rejects, `write_test` returns
/// [`GenError::TautologicalTest`] and nothing is written.
#[inline]
pub fn write_test(path: &Path, emitted: &EmittedTest<'_>) -> Result<PathBuf, GenError> {
    let contents = assemble(emitted);

    let parse_err = syn::parse_file(&contents)
        .err()
        .map(|err| GenError::InvalidRust {
            test_name: emitted.test_name.to_string(),
            reason: err.to_string(),
        });

    let cert_result = verify_test_independence(&contents, emitted.op_under_test);
    let cert_err = cert_result.as_ref().err().map(|err| GenError::InvalidRust {
        test_name: emitted.test_name.to_string(),
        reason: format!("independence certificate parse failure: {err}"),
    });

    match (parse_err, cert_err) {
        (Some(e1), Some(e2)) => return Err(GenError::Multiple(vec![e1, e2])),
        (Some(e), None) | (None, Some(e)) => return Err(e),
        (None, None) => {}
    }

    let certificate = match cert_result {
        Ok(certificate) => certificate,
        Err(err) => {
            return Err(GenError::InvalidRust {
                test_name: emitted.test_name.to_string(),
                reason: format!("independence certificate parse failure: {err}"),
            });
        }
    };

    if let CertificateVerdict::SuspectedTautology {
        line,
        call_path,
        hint,
    } = certificate.verdict
    {
        return Err(GenError::TautologicalTest {
            test_name: emitted.test_name.to_string(),
            op: emitted.op_under_test.to_string(),
            line,
            call_path,
            hint,
        });
    }

    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(path, contents)?;
    Ok(path.to_path_buf())
}

fn assemble(emitted: &EmittedTest<'_>) -> String {
    let mut out = String::new();
    out.push_str(emitted.provenance);
    out.push_str("// rendered template follows for auditability:\n");
    for line in emitted.rendered_template.lines() {
        out.push_str("// ");
        out.push_str(line);
        out.push('\n');
    }
    out.push('\n');
    out.push_str(emitted.rust);
    if !emitted.rust.ends_with('\n') {
        out.push('\n');
    }
    out
}