preprocess: add preprocessor module with include resolver
This commit is contained in:
parent
731c27a4be
commit
2f85ea9f24
|
@ -2,6 +2,7 @@
|
||||||
<module type="CPP_MODULE" version="4">
|
<module type="CPP_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/librashader-preprocess/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/librashader-presets/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/librashader-presets/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
|
|
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -8,6 +8,14 @@ version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
|
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "librashader-preprocess"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"librashader-presets",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "librashader-presets"
|
name = "librashader-presets"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"librashader-presets"
|
"librashader-presets",
|
||||||
|
"librashader-preprocess"
|
||||||
]
|
]
|
10
librashader-preprocess/Cargo.toml
Normal file
10
librashader-preprocess/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "librashader-preprocess"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
librashader-presets = { path = "../librashader-presets" }
|
14
librashader-preprocess/src/error.rs
Normal file
14
librashader-preprocess/src/error.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum PreprocessError {
|
||||||
|
#[error("the version header was missing")]
|
||||||
|
MissingVersionHeader,
|
||||||
|
#[error("the file was not found during resolution")]
|
||||||
|
IOError(PathBuf, std::io::Error),
|
||||||
|
#[error("unexpected end of file")]
|
||||||
|
UnexpectedEof,
|
||||||
|
#[error("unexpected end of line")]
|
||||||
|
UnexpectedEol(usize),
|
||||||
|
}
|
90
librashader-preprocess/src/include.rs
Normal file
90
librashader-preprocess/src/include.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::str::Lines;
|
||||||
|
use std::path::Path;
|
||||||
|
use crate::PreprocessError;
|
||||||
|
|
||||||
|
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &'static str = "#extension GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE : require";
|
||||||
|
|
||||||
|
trait PushLine {
|
||||||
|
fn push_line(&mut self, str: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushLine for String {
|
||||||
|
fn push_line(&mut self, str: &str) {
|
||||||
|
self.push_str(str);
|
||||||
|
self.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_file(path: impl AsRef<Path>) -> Result<String, PreprocessError> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let mut source = String::new();
|
||||||
|
File::open(path).and_then(|mut f| f.read_to_string(&mut source))
|
||||||
|
.map_err(|e| PreprocessError::IOError(path.to_path_buf(), e))?;
|
||||||
|
Ok(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_source(path: impl AsRef<Path>) -> Result<String, PreprocessError> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let source = read_file(path)?;
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
let source = source.trim();
|
||||||
|
let mut lines = source.lines();
|
||||||
|
|
||||||
|
if let Some(header) = lines.next() {
|
||||||
|
if !header.starts_with("#version ") {
|
||||||
|
return Err(PreprocessError::MissingVersionHeader)
|
||||||
|
}
|
||||||
|
output.push_line(header);
|
||||||
|
} else {
|
||||||
|
return Err(PreprocessError::UnexpectedEof)
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_line(GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE);
|
||||||
|
mark_line(2, path.file_name().and_then(|f| f.to_str()).unwrap_or(""), &mut output);
|
||||||
|
preprocess(lines, path, &mut output)?;
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_line(line_no: usize, comment: &str, output: &mut String) {
|
||||||
|
output.push_line(&format!("#line {} \"{}\"", line_no, comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preprocess(lines: Lines, file_name: impl AsRef<Path>, output: &mut String) -> Result<(), PreprocessError> {
|
||||||
|
let file_name = file_name.as_ref();
|
||||||
|
let include_path = file_name.parent().unwrap();
|
||||||
|
let file_name = file_name.file_name().and_then(|f| f.to_str()).unwrap_or("");
|
||||||
|
|
||||||
|
for (line_no, line) in lines.enumerate() {
|
||||||
|
if line.starts_with("#include ") {
|
||||||
|
let include_file = line["#include ".len()..].trim().trim_matches('"');
|
||||||
|
if include_file.is_empty() {
|
||||||
|
return Err(PreprocessError::UnexpectedEol(line_no))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut include_path = include_path.to_path_buf();
|
||||||
|
include_path.push(include_file);
|
||||||
|
|
||||||
|
let source = read_file(&include_path)?;
|
||||||
|
let source = source.trim();
|
||||||
|
let lines = source.lines();
|
||||||
|
|
||||||
|
let include_file = include_path.file_name().and_then(|f| f.to_str()).unwrap_or("");
|
||||||
|
mark_line(1, include_file, output);
|
||||||
|
preprocess(lines, include_path, output)?;
|
||||||
|
mark_line(line_no + 1, file_name, output);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if line.starts_with("#endif") || line.starts_with("#pragma") {
|
||||||
|
output.push_line(line);
|
||||||
|
mark_line(line_no + 2, file_name, output);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_line(line)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
15
librashader-preprocess/src/lib.rs
Normal file
15
librashader-preprocess/src/lib.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
mod error;
|
||||||
|
mod include;
|
||||||
|
|
||||||
|
pub use error::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::include::read_source;
|
||||||
|
#[test]
|
||||||
|
pub fn preprocess_file() {
|
||||||
|
let result = read_source("../test/slang-shaders/blurs/shaders/royale/blur3x3-last-pass.slang").unwrap();
|
||||||
|
eprintln!("{result}")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue