shader_sense/validator/
naga.rs1use naga::{
4 front::wgsl::{self, ParseError},
5 valid::{Capabilities, ValidationFlags},
6};
7use std::path::Path;
8
9use crate::{
10 position::{ShaderFileRange, ShaderPosition},
11 shader::{ShaderParams, ShaderStage},
12 shader_error::{ShaderDiagnostic, ShaderDiagnosticList, ShaderDiagnosticSeverity, ShaderError},
13};
14
15use super::validator::ValidatorImpl;
16
17pub struct Naga {}
18
19impl Naga {
20 pub fn new() -> Self {
21 Self {}
22 }
23 fn from_parse_err(err: ParseError, file_path: &Path, shader_content: &str) -> ShaderDiagnostic {
24 let error = err.emit_to_string(shader_content);
25 let loc = err.location(shader_content);
26 if let Some(loc) = loc {
27 ShaderDiagnostic {
28 severity: ShaderDiagnosticSeverity::Error,
29 error,
30 range: ShaderFileRange::new(
31 file_path.into(),
32 ShaderPosition::new(loc.line_number - 1, loc.line_position),
33 ShaderPosition::new(loc.line_number - 1, loc.line_position),
34 ),
35 }
36 } else {
37 ShaderDiagnostic {
38 severity: ShaderDiagnosticSeverity::Error,
39 error,
40 range: ShaderFileRange::zero(file_path.into()),
41 }
42 }
43 }
44}
45impl ValidatorImpl for Naga {
46 fn validate_shader(
47 &self,
48 shader_content: &str,
49 file_path: &Path,
50 _params: &ShaderParams,
51 _include_callback: &mut dyn FnMut(&Path) -> Option<String>,
52 ) -> Result<ShaderDiagnosticList, ShaderError> {
53 let module = match wgsl::parse_str(shader_content)
54 .map_err(|err| Self::from_parse_err(err, file_path, shader_content))
55 {
56 Ok(module) => module,
57 Err(diag) => {
58 return Ok(ShaderDiagnosticList::from(diag));
59 }
60 };
61
62 let mut validator =
63 naga::valid::Validator::new(ValidationFlags::all(), Capabilities::all());
64 if let Err(error) = validator.validate(&module) {
65 let mut list = ShaderDiagnosticList::empty();
66 for (span, _) in error.spans() {
67 let loc = span.location(shader_content);
68 list.push(ShaderDiagnostic {
69 severity: ShaderDiagnosticSeverity::Error,
70 error: error.emit_to_string(""),
71 range: ShaderFileRange::new(
72 file_path.into(),
73 ShaderPosition::new(loc.line_number - 1, loc.line_position),
74 ShaderPosition::new(loc.line_number - 1, loc.line_position),
75 ),
76 });
77 }
78 if list.is_empty() {
79 Err(ShaderError::InternalErr(
80 error.emit_to_string(shader_content),
81 ))
82 } else {
83 Ok(list)
84 }
85 } else {
86 Ok(ShaderDiagnosticList::empty())
87 }
88 }
89 fn support(&self, shader_stage: ShaderStage) -> bool {
90 match shader_stage {
91 ShaderStage::Vertex | ShaderStage::Fragment | ShaderStage::Compute => true,
92 _ => false,
93 }
94 }
95}