preprocess: implement meta parsing
This commit is contained in:
parent
de161373a9
commit
394e09678d
|
@ -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!()
|
||||
}
|
||||
}
|
|
@ -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:?}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 != ¶meter {
|
||||
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())
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue