preprocess: implement meta parsing

This commit is contained in:
chyyran 2022-10-21 23:37:47 -04:00
parent de161373a9
commit 394e09678d
4 changed files with 125 additions and 6 deletions

View file

@ -1,5 +1,7 @@
use std::convert::Infallible;
use std::path::PathBuf;
use thiserror::Error;
use librashader::ShaderParameter;
#[derive(Error, Debug)]
pub enum PreprocessError {
@ -11,4 +13,19 @@ pub enum PreprocessError {
UnexpectedEof,
#[error("unexpected end of line")]
UnexpectedEol(usize),
#[error("error parsing pragma")]
PragmaParseError(String),
#[error("duplicate parameter but arguments do not match")]
DuplicateParameterError(String),
#[error("shader format is unknown or not found")]
UnknownShaderFormat,
#[error("tried to declare shader format twice")]
DuplicateShaderFormat,
}
impl From<Infallible> for PreprocessError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}

View file

@ -7,6 +7,8 @@ pub use error::*;
#[cfg(test)]
mod test {
use crate::include::read_source;
use crate::pragma;
#[test]
pub fn preprocess_file() {
let result =
@ -14,4 +16,15 @@ mod test {
.unwrap();
eprintln!("{result}")
}
#[test]
pub fn get_param_pragmas() {
let result =
read_source("../test/slang-shaders/crt/shaders/crt-maximus-royale/src/ntsc_pass1.slang")
.unwrap();
let params = pragma::parse_pragma_meta(result)
.unwrap();
eprintln!("{params:?}")
}
}

View file

@ -1,5 +1,91 @@
use librashader::ShaderParameter;
use std::str::FromStr;
use nom::bytes::complete::{is_not, tag, take_until, take_while};
use nom::combinator::map_res;
use nom::IResult;
use nom::number::complete::float;
use nom::sequence::delimited;
use librashader::{ShaderFormat, ShaderParameter};
use crate::PreprocessError;
pub fn parse_pragma_parameter(source: impl AsRef<str>) -> Vec<ShaderParameter> {
fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessError>{
fn parse_parameter_string_inner(input: &str) -> IResult<&str, ShaderParameter> {
let (input, _) = tag("#pragma parameter ")(input)?;
let (input, name) = take_while(|c| c != ' ')(input)?;
let (input, _) = tag(" ")(input)?;
let (input, description) = delimited(tag("\""), is_not("\""), tag("\""))(input)?;
let (input, _) = tag(" ")(input)?;
let (input, initial) = float(input)?;
let (input, _) = tag(" ")(input)?;
let (input, minimum) = float(input)?;
let (input, _) = tag(" ")(input)?;
let (input, maximum) = float(input)?;
let (input, _) = tag(" ")(input)?;
let (input, step) = float(input)?;
Ok((input, ShaderParameter {
id: name.to_string(),
description: description.to_string(),
initial,
minimum,
maximum,
step
}))
}
if let Ok((_, parameter)) = parse_parameter_string_inner(input) {
Ok(parameter)
} else {
Err(PreprocessError::PragmaParseError(input.to_string()))
}
}
pub fn parse_pragma_meta(source: impl AsRef<str>) -> Result<(ShaderFormat, Vec<ShaderParameter>), PreprocessError> {
let source = source.as_ref();
let mut parameters: Vec<ShaderParameter> = Vec::new();
let mut format = ShaderFormat::default();
for line in source.lines() {
if line.starts_with("#pragma parameter ") {
let parameter = parse_parameter_string(line)?;
if let Some(existing) = parameters.iter().find(|&p| p.id == parameter.id) {
if existing != &parameter {
return Err(PreprocessError::DuplicateParameterError(parameter.id))
}
} else {
parameters.push(parameter);
}
}
if line.starts_with("#pragma format ") {
if format != ShaderFormat::Unknown {
return Err(PreprocessError::DuplicateShaderFormat)
}
let format_string = line["#pragma format ".len()..].trim();
format = ShaderFormat::from_str(&format_string)?;
if format == ShaderFormat::Unknown {
return Err(PreprocessError::UnknownShaderFormat)
}
}
}
Ok((format, parameters))
}
#[cfg(test)]
mod test {
use librashader::ShaderParameter;
use crate::pragma::parse_parameter_string;
#[test]
fn parses_parameter_pragma() {
assert_eq!(ShaderParameter {
id: "exc".to_string(),
description: "orizontal correction hack (games where players stay at center)".to_string(),
initial: 0.0,
minimum: -10.0,
maximum: 10.0,
step: 0.25
}, parse_parameter_string(r#"#pragma parameter exc "orizontal correction hack (games where players stay at center)" 0.0 -10.0 10.0 0.25"#).unwrap())
}
}

View file

@ -9,6 +9,7 @@ pub struct ShaderSource {
pub format: ShaderFormat,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ShaderParameter {
pub id: String,
pub description: String,
@ -19,7 +20,9 @@ pub struct ShaderParameter {
}
#[repr(u32)]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
pub enum ShaderFormat {
#[default]
Unknown = 0,
/* 8-bit */
@ -98,9 +101,9 @@ impl FromStr for ShaderFormat {
"R32G32_UINT" => Self::R32G32Uint,
"R32G32_SINT" => Self::R32G32Sint,
"R32G32_SFLOAT" => Self::R32G32Sfloat,
"R32G32B32A32_UINT" => Self::R32G32A32Uint,
"R32G32B32A32_SINT" => Self::R32G32A32Sint,
"R32G32B32A32_SFLOAT" => Self::R32G32SA32float,
"R32G32B32A32_UINT" => Self::R32G32B32A32Uint,
"R32G32B32A32_SINT" => Self::R32G32B32A32Sint,
"R32G32B32A32_SFLOAT" => Self::R32G32B32A32Sfloat,
_ => Self::Unknown,
})
}