glsl-lang-pp 0.4.1

GLSL language preprocessor
Documentation
use thiserror::Error;

use lang_util::{
    located::{Located, LocatedBuilder},
    FileId,
};

use crate::{last::LocatedIterator, parser, types::path::ParsedPath};

use super::{
    event::Event,
    expand::{ExpandEvent, ExpandOne},
    ProcessorState,
};

pub fn parse(input: &str) -> parser::Ast {
    parser::Parser::new(input).parse()
}

#[derive(Debug, PartialEq, Eq, Error)]
pub enum ProcessStrError {
    #[error("an include was requested without a filesystem context")]
    IncludeRequested(ParsedPath),
}

pub fn process(input: &str, state: ProcessorState) -> ExpandStr {
    let file_id = FileId::new(0);
    let ast = parser::Parser::new(input).parse();
    ExpandStr {
        inner: ExpandOne::new((file_id, ast), state),
        final_state: None,
    }
}

pub struct ExpandStr {
    inner: ExpandOne,
    final_state: Option<ProcessorState>,
}

impl ExpandStr {
    pub fn tokenize(
        self,
        current_version: u16,
        target_vulkan: bool,
        registry: &crate::exts::Registry,
    ) -> crate::last::Tokenizer<'_, Self> {
        crate::last::Tokenizer::new(self, current_version, target_vulkan, registry)
    }

    pub fn into_state(mut self) -> Option<ProcessorState> {
        self.final_state.take()
    }
}

impl Iterator for ExpandStr {
    type Item = Result<Event, Located<ProcessStrError>>;

    fn next(&mut self) -> Option<Self::Item> {
        let event = self.inner.next()?;
        match event {
            ExpandEvent::Event(event) => Some(Ok(event)),
            ExpandEvent::EnterFile(node, path) => Some(Err(LocatedBuilder::new()
                .pos(node.text_range())
                .resolve_file(self.inner.location())
                .finish(ProcessStrError::IncludeRequested(path)))),
            ExpandEvent::Completed(state) => {
                self.final_state = Some(state);
                None
            }
        }
    }
}

impl LocatedIterator for ExpandStr {
    fn location(&self) -> &crate::processor::expand::ExpandLocation {
        self.inner.location()
    }
}

#[cfg(test)]
mod tests {
    fn assert_send<T: Send>() {}

    #[test]
    fn test_error_send() {
        assert_send::<super::ProcessStrError>();
    }
}