[naga-cli] Abstract out parsing of input file.

This commit is contained in:
Jim Blandy 2023-12-12 14:48:03 -08:00
parent e1baa5a56e
commit 79a6a4b0d2

View File

@ -236,27 +236,16 @@ impl std::error::Error for CliError {}
fn run() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
// Initialize default parameters
//TODO: read the parameters from RON?
let mut params = Parameters::default();
// Parse commandline arguments
let args: Args = argh::from_env();
if args.version {
println!("{}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
let (input_path, input) = if let Some(path) = args.files.first() {
let path = Path::new(path);
(path, fs::read(path)?)
} else if let Some(path) = &args.stdin_file_path {
let mut input = vec![];
std::io::stdin().lock().read_to_end(&mut input)?;
(Path::new(path), input)
} else {
return Err(CliError("Input file path is not specified").into());
};
let output_paths = args.files.get(1..).unwrap_or(&[]);
// Initialize default parameters
//TODO: read the parameters from RON?
let mut params = Parameters::default();
// Update parameters from commandline arguments
if let Some(bits) = args.validate {
@ -286,10 +275,10 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
};
params.entry_point = args.entry_point;
if let Some(version) = args.profile {
if let Some(ref version) = args.profile {
params.glsl.version = version.0;
}
if let Some(model) = args.shader_model {
if let Some(ref model) = args.shader_model {
params.hlsl.shader_model = model.0;
}
params.keep_coordinate_space = args.keep_coordinate_space;
@ -302,68 +291,22 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
!params.keep_coordinate_space,
);
let (mut module, input_text) = match Path::new(&input_path)
.extension()
.ok_or(CliError("Input filename has no extension"))?
.to_str()
.ok_or(CliError("Input filename not valid unicode"))?
{
"bin" => (bincode::deserialize(&input)?, None),
"spv" => naga::front::spv::parse_u8_slice(&input, &params.spv_in).map(|m| (m, None))?,
"wgsl" => {
let input = String::from_utf8(input)?;
let result = naga::front::wgsl::parse_str(&input);
match result {
Ok(v) => (v, Some(input)),
Err(ref e) => {
e.emit_to_stderr_with_path(&input, input_path);
return Err(CliError("Could not parse WGSL").into());
}
}
}
ext @ ("vert" | "frag" | "comp" | "glsl") => {
let input = String::from_utf8(input)?;
let mut parser = naga::front::glsl::Frontend::default();
(
parser
.parse(
&naga::front::glsl::Options {
stage: match ext {
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
"glsl" => {
let internal_name = input_path.to_string_lossy();
match Path::new(&internal_name[..internal_name.len()-5])
.extension()
.ok_or(CliError("Input filename ending with .glsl has no internal extension"))?
.to_str()
.ok_or(CliError("Input filename not valid unicode"))?
{
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
_ => unreachable!(),
}
},
_ => unreachable!(),
},
defines: Default::default(),
},
&input,
)
.unwrap_or_else(|errors| {
let filename = input_path.file_name().and_then(std::ffi::OsStr::to_str);
emit_glsl_parser_error(errors, filename.unwrap_or("glsl"), &input);
std::process::exit(1);
}),
Some(input),
)
}
_ => return Err(CliError("Unknown input file extension").into()),
let (input_path, input) = if let Some(path) = args.files.first() {
let path = Path::new(path);
(path, fs::read(path)?)
} else if let Some(path) = &args.stdin_file_path {
let mut input = vec![];
std::io::stdin().lock().read_to_end(&mut input)?;
(Path::new(path), input)
} else {
return Err(CliError("Input file path is not specified").into());
};
let Parsed {
mut module,
input_text,
} = parse_input(input_path, input, &params)?;
// Include debugging information if requested.
if args.generate_debug_symbols {
if let Some(ref input_text) = input_text {
@ -384,6 +327,8 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
}
}
let output_paths = args.files.get(1..).unwrap_or(&[]);
// Decide which capabilities our output formats can support.
let validation_caps =
output_paths
@ -469,6 +414,84 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
struct Parsed {
module: naga::Module,
input_text: Option<String>,
}
fn parse_input(
input_path: &Path,
input: Vec<u8>,
params: &Parameters,
) -> Result<Parsed, Box<dyn std::error::Error>> {
let (module, input_text) = match Path::new(&input_path)
.extension()
.ok_or(CliError("Input filename has no extension"))?
.to_str()
.ok_or(CliError("Input filename not valid unicode"))?
{
"bin" => (bincode::deserialize(&input)?, None),
"spv" => naga::front::spv::parse_u8_slice(&input, &params.spv_in).map(|m| (m, None))?,
"wgsl" => {
let input = String::from_utf8(input)?;
let result = naga::front::wgsl::parse_str(&input);
match result {
Ok(v) => (v, Some(input)),
Err(ref e) => {
let message = format!(
"Could not parse WGSL:\n{}",
e.emit_to_string_with_path(&input, input_path)
);
return Err(message.into());
}
}
}
ext @ ("vert" | "frag" | "comp" | "glsl") => {
let input = String::from_utf8(input)?;
let mut parser = naga::front::glsl::Frontend::default();
(
parser
.parse(
&naga::front::glsl::Options {
stage: match ext {
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
"glsl" => {
let internal_name = input_path.to_string_lossy();
match Path::new(&internal_name[..internal_name.len()-5])
.extension()
.ok_or(CliError("Input filename ending with .glsl has no internal extension"))?
.to_str()
.ok_or(CliError("Input filename not valid unicode"))?
{
"vert" => naga::ShaderStage::Vertex,
"frag" => naga::ShaderStage::Fragment,
"comp" => naga::ShaderStage::Compute,
_ => unreachable!(),
}
},
_ => unreachable!(),
},
defines: Default::default(),
},
&input,
)
.unwrap_or_else(|errors| {
let filename = input_path.file_name().and_then(std::ffi::OsStr::to_str);
emit_glsl_parser_error(errors, filename.unwrap_or("glsl"), &input);
std::process::exit(1);
}),
Some(input),
)
}
_ => return Err(CliError("Unknown input file extension").into()),
};
Ok(Parsed { module, input_text })
}
fn write_output(
module: &naga::Module,
info: &Option<naga::valid::ModuleInfo>,