wgsldoc 1.0.0-alpha

Documentation generator for WGSL shaders
Documentation
//! Module for parsing WGSL types using Pest and converting them into [`Type`] model.

use super::{error::ParsingError, FromPest, Rule};
use crate::models::types::{PathType, Primitive, Type, Vector, VectorDimension};
use pest::iterators::Pair;
use std::str::FromStr;
use thiserror::Error;

impl FromPest for Type {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError>
    where
        Self: Sized,
    {
        match element.as_rule() {
            Rule::TYPE => {
                let mut ty = Type::default();

                for type_element in element.into_inner() {
                    match type_element.as_rule() {
                        Rule::PRIMITIVE => {
                            ty = Type::Primitive(Primitive::from_pest(type_element)?);
                        }
                        Rule::VECTOR => {
                            ty = Type::Vector(Vector::from_pest(type_element)?);
                        }
                        Rule::PATH_TYPE => {
                            ty = Type::Path(PathType::from_pest(type_element)?);
                        }
                        _ => {}
                    }
                }

                Ok(ty)
            }
            _ => Err(ParsingError::InvalidPestRule {
                expected: Rule::TYPE,
                found: element.as_rule(),
            }),
        }
    }
}

/// Error for invalid primitive types during parsing.
#[derive(Debug, Error)]
#[error("Invalid primitive type `{0}`; available are bool, f32, f64, u8, u16, u32, u64, i8, i16, i32, i64")]
pub struct InvalidPrimitiveType(String);

impl FromStr for Primitive {
    type Err = InvalidPrimitiveType;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Primitive::*;

        match s {
            "bool" => Ok(Bool),
            "f32" => Ok(Float32),
            "f64" => Ok(Float64),
            "u8" => Ok(Uint8),
            "u16" => Ok(Uint16),
            "u32" => Ok(Uint32),
            "u64" => Ok(Uint64),
            "i8" => Ok(Sint8),
            "i16" => Ok(Sint16),
            "i32" => Ok(Sint32),
            "i64" => Ok(Sint64),
            _ => Err(InvalidPrimitiveType(s.to_owned())),
        }
    }
}

impl FromPest for Primitive {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError>
    where
        Self: Sized,
    {
        match element.as_rule() {
            Rule::PRIMITIVE => Ok(Primitive::from_str(element.as_span().as_str())?),
            _ => Err(ParsingError::InvalidPestRule {
                expected: Rule::PRIMITIVE,
                found: element.as_rule(),
            }),
        }
    }
}

impl FromPest for Vector {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError>
    where
        Self: Sized,
    {
        match element.as_rule() {
            Rule::VECTOR => {
                let mut dimension = VectorDimension::default();
                let mut ty = Primitive::default();

                for vector_element in element.into_inner() {
                    match vector_element.as_rule() {
                        Rule::VECTOR_DIMENSION => {
                            dimension = VectorDimension::from_pest(vector_element)?;
                        }
                        Rule::PRIMITIVE => {
                            ty = Primitive::from_pest(vector_element)?;
                        }
                        _ => {}
                    }
                }

                Ok(Vector::new(dimension, ty))
            }
            _ => Err(ParsingError::InvalidPestRule {
                expected: Rule::VECTOR,
                found: element.as_rule(),
            }),
        }
    }
}

/// Error for invalid vector dimensions during parsing.
#[derive(Debug, Error)]
#[error("Invalid vector dimension `{0}`; available are 2, 3, 4")]
pub struct InvalidVectorDimension(String);

impl FromStr for VectorDimension {
    type Err = InvalidPrimitiveType;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use VectorDimension::*;

        match s {
            "2" => Ok(D2),
            "3" => Ok(D3),
            "4" => Ok(D4),
            _ => Err(InvalidPrimitiveType(s.to_owned())),
        }
    }
}

impl FromPest for VectorDimension {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError>
    where
        Self: Sized,
    {
        match element.as_rule() {
            Rule::VECTOR_DIMENSION => Ok(VectorDimension::from_str(element.as_span().as_str())?),
            _ => Err(ParsingError::InvalidPestRule {
                expected: Rule::VECTOR_DIMENSION,
                found: element.as_rule(),
            }),
        }
    }
}

impl FromPest for PathType {
    fn from_pest(element: Pair<'_, Rule>) -> Result<Self, ParsingError>
    where
        Self: Sized,
    {
        match element.as_rule() {
            Rule::PATH_TYPE => {
                let mut module = None;
                let mut name = String::new();

                for path_type_element in element.into_inner() {
                    match path_type_element.as_rule() {
                        Rule::MODULE => {
                            module = Some(path_type_element.as_span().as_str().to_owned())
                                .filter(|s| !s.is_empty());
                        }
                        Rule::IDENT => {
                            name = path_type_element.as_span().as_str().to_owned();
                        }
                        _ => {}
                    }
                }

                Ok(PathType::new(module, name))
            }
            _ => Err(ParsingError::InvalidPestRule {
                expected: Rule::PATH_TYPE,
                found: element.as_rule(),
            }),
        }
    }
}