2022-10-22 17:54:06 +11:00
|
|
|
use crate::{PreprocessError, SourceOutput};
|
2022-10-21 16:12:17 +11:00
|
|
|
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-21 16:12:17 +11:00
|
|
|
|
2022-10-23 15:59:18 +11:00
|
|
|
#[cfg(feature = "line_directives")]
|
2022-11-22 08:21:50 +11:00
|
|
|
const GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE: &str =
|
2022-10-23 17:36:41 +11:00
|
|
|
"#extension GL_GOOGLE_cpp_style_line_directive : require";
|
2022-10-21 16:12:17 +11:00
|
|
|
|
|
|
|
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))
|
2022-10-21 16:12:17 +11:00
|
|
|
.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);
|
2022-10-21 16:12:17 +11:00
|
|
|
}
|
|
|
|
output.push_line(header);
|
|
|
|
} else {
|
2022-10-22 12:04:00 +11:00
|
|
|
return Err(PreprocessError::UnexpectedEof);
|
2022-10-21 16:12:17 +11:00
|
|
|
}
|
|
|
|
|
2022-10-23 15:59:18 +11:00
|
|
|
#[cfg(feature = "line_directives")]
|
2022-10-21 16:12:17 +11:00
|
|
|
output.push_line(GL_GOOGLE_CPP_STYLE_LINE_DIRECTIVE);
|
2022-10-23 15:59:18 +11:00
|
|
|
|
2022-10-22 12:04:00 +11:00
|
|
|
output.mark_line(2, path.file_name().and_then(|f| f.to_str()).unwrap_or(""));
|
2022-10-21 16:12:17 +11:00
|
|
|
preprocess(lines, path, &mut output)?;
|
|
|
|
|
|
|
|
Ok(output)
|
|
|
|
}
|
|
|
|
|
2022-10-22 12:04:00 +11:00
|
|
|
fn preprocess(
|
|
|
|
lines: Lines,
|
|
|
|
file_name: impl AsRef<Path>,
|
|
|
|
output: &mut String,
|
|
|
|
) -> Result<(), PreprocessError> {
|
2022-10-21 16:12:17 +11:00
|
|
|
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));
|
2022-10-21 16:12:17 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2022-10-21 16:12:17 +11:00
|
|
|
preprocess(lines, include_path, output)?;
|
2022-10-22 12:04:00 +11:00
|
|
|
output.mark_line(line_no + 1, file_name);
|
2022-10-21 16:12:17 +11:00
|
|
|
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);
|
2022-10-21 16:12:17 +11:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
output.push_line(line)
|
|
|
|
}
|
|
|
|
Ok(())
|
2022-10-22 12:04:00 +11:00
|
|
|
}
|