Skip to content

Commit

Permalink
[naga-cli] Abstract out parsing of input file.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimblandy committed Dec 12, 2023
1 parent ecc301e commit 3f5ea9b
Showing 1 changed file with 100 additions and 77 deletions.
177 changes: 100 additions & 77 deletions naga-cli/src/bin/naga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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>,
Expand Down

0 comments on commit 3f5ea9b

Please sign in to comment.