librashader/librashader-preprocess/src/include.rs

103 lines
3.1 KiB
Rust
Raw Normal View History

2022-10-22 12:04:00 +11:00
use crate::PreprocessError;
use std::fs::File;
use std::io::Read;
use std::path::Path;
2022-10-22 12:04:00 +11:00
use std::str::Lines;
2022-10-22 12:04:00 +11:00
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &'static str =
"#extension GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE : require";
2022-10-22 12:04:00 +11:00
trait SourceOutput {
fn push_line(&mut self, str: &str);
2022-10-22 12:04:00 +11:00
fn mark_line(&mut self, line_no: usize, comment: &str) {
self.push_line(&format!("#line {} \"{}\"", line_no, comment))
}
}
2022-10-22 12:04:00 +11:00
impl SourceOutput 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();
2022-10-22 12:04:00 +11:00
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 ") {
2022-10-22 12:04:00 +11:00
return Err(PreprocessError::MissingVersionHeader);
}
output.push_line(header);
} else {
2022-10-22 12:04:00 +11:00
return Err(PreprocessError::UnexpectedEof);
}
output.push_line(GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE);
2022-10-22 12:04:00 +11:00
output.mark_line(2, path.file_name().and_then(|f| f.to_str()).unwrap_or(""));
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))
}
2022-10-22 12:04:00 +11:00
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() {
2022-10-22 12:04:00 +11:00
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();
2022-10-22 12:04:00 +11:00
let include_file = include_path
.file_name()
.and_then(|f| f.to_str())
.unwrap_or("");
output.mark_line(1, include_file);
preprocess(lines, include_path, output)?;
2022-10-22 12:04:00 +11:00
output.mark_line(line_no + 1, file_name);
continue;
}
if line.starts_with("#endif") || line.starts_with("#pragma") {
output.push_line(line);
2022-10-22 12:04:00 +11:00
output.mark_line(line_no + 2, file_name);
continue;
}
output.push_line(line)
}
Ok(())
2022-10-22 12:04:00 +11:00
}