librashader/librashader-preprocess/src/pragma.rs

114 lines
3.7 KiB
Rust
Raw Normal View History

2022-10-23 15:59:18 +11:00
use crate::PreprocessError;
use librashader::{ShaderFormat, ShaderParameter};
2022-10-22 14:37:47 +11:00
use nom::bytes::complete::{is_not, tag, take_until, take_while};
use nom::combinator::map_res;
use nom::number::complete::float;
use nom::sequence::delimited;
2022-10-23 15:59:18 +11:00
use nom::IResult;
use std::str::FromStr;
2022-10-22 12:04:00 +11:00
#[derive(Debug)]
pub(crate) struct ShaderMeta {
pub(crate) format: ShaderFormat,
pub(crate) parameters: Vec<ShaderParameter>,
2022-10-23 15:59:18 +11:00
pub(crate) name: Option<String>,
}
2022-10-22 14:37:47 +11:00
2022-10-23 15:59:18 +11:00
fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessError> {
2022-10-22 14:37:47 +11:00
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)?;
2022-10-23 15:59:18 +11:00
Ok((
input,
ShaderParameter {
id: name.to_string(),
description: description.to_string(),
initial,
minimum,
maximum,
step,
},
))
2022-10-22 14:37:47 +11:00
}
if let Ok((_, parameter)) = parse_parameter_string_inner(input) {
Ok(parameter)
} else {
Err(PreprocessError::PragmaParseError(input.to_string()))
}
}
pub(crate) fn parse_pragma_meta(source: impl AsRef<str>) -> Result<ShaderMeta, PreprocessError> {
2022-10-22 14:37:47 +11:00
let source = source.as_ref();
let mut parameters: Vec<ShaderParameter> = Vec::new();
let mut format = ShaderFormat::default();
let mut name = None;
2022-10-22 14:37:47 +11:00
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 {
2022-10-23 15:59:18 +11:00
return Err(PreprocessError::DuplicatePragmaError(parameter.id));
2022-10-22 14:37:47 +11:00
}
} else {
parameters.push(parameter);
}
}
if line.starts_with("#pragma format ") {
if format != ShaderFormat::Unknown {
2022-10-23 15:59:18 +11:00
return Err(PreprocessError::DuplicatePragmaError(line.to_string()));
2022-10-22 14:37:47 +11:00
}
let format_string = line["#pragma format ".len()..].trim();
format = ShaderFormat::from_str(&format_string)?;
if format == ShaderFormat::Unknown {
2022-10-23 15:59:18 +11:00
return Err(PreprocessError::UnknownShaderFormat);
2022-10-22 14:37:47 +11:00
}
}
if line.starts_with("#pragma name ") {
if name.is_some() {
return Err(PreprocessError::DuplicatePragmaError(line.to_string()));
}
name = Some(line.trim().to_string())
}
2022-10-22 14:37:47 +11:00
}
2022-10-23 15:59:18 +11:00
Ok(ShaderMeta {
name,
format,
parameters,
})
2022-10-22 14:37:47 +11:00
}
#[cfg(test)]
mod test {
use crate::pragma::parse_parameter_string;
2022-10-23 15:59:18 +11:00
use librashader::ShaderParameter;
2022-10-22 14:37:47 +11:00
#[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())
}
2022-10-23 15:59:18 +11:00
}