vyre-libs 0.6.1

vyre Category A library ecosystem - pure-IR compositions over vyre-ops hardware primitives
Documentation
use std::path::Path;

use super::conditional_directives::{
    apply_else, apply_endif, apply_ifdef, apply_ifexpr, conditionals_active,
};
use super::directive_diagnostics::{
    reject_active_error_directive, reject_unterminated_conditionals,
};
use super::directive_emission::{
    emit_active_row, emit_trailing_active_bytes, flush_before_directive, flush_final_active_bytes,
    row_token_span,
};
use super::directive_state::DirectiveWalkState;
use super::file_inputs::PreparedFile;
use super::ifdef_truth_batch::ensure_ifdef_truth_batch;
use super::include_directives::apply_include;
use super::macro_directives::{apply_define, apply_undef};
use super::stage_trace::StageTrace;
use super::PreprocessRun;
use crate::parsing::c::preprocess::gpu_pipeline::token_provenance::record_direct_token_provenance;
use crate::parsing::c::preprocess::gpu_pipeline::DirectivePayload;

pub(super) fn walk_directives(
    run: &mut PreprocessRun<'_>,
    file_path: &Path,
    source: &[u8],
    depth: u32,
    prepared: PreparedFile,
    trace: &mut StageTrace<'_>,
) -> Result<(), String> {
    let classified = prepared.classified;
    let payloads = prepared.payloads;
    let classified = classified.as_ref();
    let payloads = payloads.as_ref();
    let directive_free = payloads.is_empty()
        || payloads
            .iter()
            .all(|payload| matches!(payload, DirectivePayload::None));
    if run.macros.is_empty() && directive_free {
        let output_base = run.output.len();
        record_direct_token_provenance(
            file_path,
            &run.stack,
            classified,
            output_base,
            &mut run.token_provenance_events,
        )?;
        run.output.extend_from_slice(&classified.source);
        trace.log("emit directive-free gpu-filtered source");
        return Ok(());
    }
    if payloads.is_empty() {
        let mut state = DirectiveWalkState::new(payloads);
        for i in 0..classified.tok_types.len() {
            let (tok_start, tok_end) = row_token_span(&classified, i)?;
            emit_active_row(&classified, &mut state, tok_start, tok_end)?;
        }
        emit_trailing_active_bytes(&classified, &mut state)?;
        flush_final_active_bytes(run, file_path, &classified, &mut state)?;
        trace.log("walk directive-free tokens");
        return Ok(());
    }
    let mut state = DirectiveWalkState::new(payloads);

    for (i, payload) in payloads.iter().enumerate() {
        let row_active = conditionals_active(&state.conditionals);
        let (tok_start, tok_end) = row_token_span(&classified, i)?;
        if !matches!(payload, DirectivePayload::None) {
            flush_before_directive(run, file_path, &classified, &mut state)?;
        }
        match payload {
            DirectivePayload::None => {
                emit_active_row(&classified, &mut state, tok_start, tok_end)?;
            }
            DirectivePayload::Define {
                name,
                name_start,
                name_len,
                args,
                args_start,
                args_len,
                body,
                body_start,
                body_len,
                is_function_like,
            } => {
                if row_active {
                    apply_define(
                        run,
                        file_path,
                        i,
                        tok_start,
                        name,
                        (*name_start, *name_len),
                        args,
                        (*args_start, *args_len),
                        body,
                        (*body_start, *body_len),
                        *is_function_like,
                        &mut state.macro_expansion_cache,
                        &mut state.live_macro_buffers_cache,
                    )?;
                    state.invalidate_ifdef_truth_cache();
                }
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Undef { name } => {
                if row_active {
                    apply_undef(
                        run,
                        file_path,
                        i,
                        tok_start,
                        name,
                        &mut state.macro_expansion_cache,
                        &mut state.live_macro_buffers_cache,
                    )?;
                    state.invalidate_ifdef_truth_cache();
                }
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Include {
                path,
                is_system,
                is_next,
            } => {
                if row_active
                    && apply_include(
                        run, file_path, path, *is_system, *is_next, i, tok_start, depth, trace,
                    )?
                {
                    state.invalidate_macro_dependent_caches();
                }
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Ifdef { value: _, negated } => {
                let guard_name = state.include_guard_ifndef_names.name_at(i);
                let precomputed_truth = if row_active && guard_name.is_none() {
                    ensure_ifdef_truth_batch(
                        run,
                        &classified,
                        &payloads,
                        &state.include_guard_ifndef_names,
                        &mut state.live_macro_buffers_cache,
                        &mut state.ifdef_truth_cache,
                        i,
                        &mut state.gpu_ifdef,
                    )?;
                    state.ifdef_truth_cache.get(&i).copied()
                } else {
                    None
                };
                apply_ifdef(
                    run,
                    file_path,
                    &classified,
                    &mut state.conditionals,
                    &mut state.live_macro_buffers_cache,
                    i,
                    tok_start,
                    *negated,
                    guard_name,
                    precomputed_truth,
                    &mut state.gpu_ifdef,
                )?;
                state.last_emit_end = tok_end;
            }
            DirectivePayload::IfExpr { value: _, is_elif } => {
                apply_ifexpr(
                    run,
                    file_path,
                    &classified,
                    &mut state.conditionals,
                    &mut state.live_macro_buffers_cache,
                    i,
                    tok_start,
                    *is_elif,
                    &mut state.gpu_if,
                )?;
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Else => {
                apply_else(run, file_path, &mut state.conditionals, i, tok_start)?;
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Endif => {
                apply_endif(run, file_path, &mut state.conditionals, i, tok_start)?;
                state.last_emit_end = tok_end;
            }
            DirectivePayload::Other => {
                if row_active {
                    reject_active_error_directive(&classified, file_path, i, tok_start, tok_end)?;
                }
                state.last_emit_end = tok_end;
            }
        }
    }

    reject_unterminated_conditionals(file_path, &state.conditionals)?;
    emit_trailing_active_bytes(&classified, &mut state)?;
    flush_final_active_bytes(run, file_path, &classified, &mut state)?;
    trace.log("walk directives");
    if std::env::var_os("VYRE_PREPROC_COUNTS").is_some() {
        let elapsed = state.walk_start.elapsed();
        tracing::debug!(
            "[preproc-counts] {} bytes={} payloads={} elapsed={:?} gpu_ifdef={} gpu_if={}",
            file_path.display(),
            source.len(),
            payloads.len(),
            elapsed,
            state.gpu_ifdef,
            state.gpu_if,
        );
    }
    Ok(())
}