Skip to content

Commit f8dd31c

Browse files
committed
extract out diagnostics parser. pls submit AMD lint output in github issues
1 parent d3c0869 commit f8dd31c

File tree

4 files changed

+128
-80
lines changed

4 files changed

+128
-80
lines changed

server/src/diagnostics_parser.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use std::{collections::HashMap, path::Path};
2+
3+
use once_cell::sync::OnceCell;
4+
5+
use regex::Regex;
6+
use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range};
7+
use url::Url;
8+
9+
use crate::{consts, opengl};
10+
11+
static RE_DIAGNOSTIC: OnceCell<Regex> = OnceCell::new();
12+
fn diagnostics_regex<T>(vendor: &T) -> &'static Regex
13+
where
14+
T: opengl::ShaderValidator + ?Sized,
15+
{
16+
RE_DIAGNOSTIC.get_or_init(|| match vendor.vendor().as_str() {
17+
"NVIDIA" => {
18+
Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap()
19+
}
20+
_ => {
21+
Regex::new(r#"^(?P<severity>ERROR|WARNING): (?P<filepath>[^?<>*|"\n]+):(?P<linenum>\d+): '[a-z]*' : (?P<output>.+)$"#).unwrap()
22+
}
23+
})
24+
}
25+
26+
static LINE_NUM_OFFSET: OnceCell<u32> = OnceCell::new();
27+
fn line_number_offset<T>(vendor: &T) -> &'static u32
28+
where
29+
T: opengl::ShaderValidator + ?Sized,
30+
{
31+
LINE_NUM_OFFSET.get_or_init(|| match vendor.vendor().as_str() {
32+
"ATI Technologies" => 0,
33+
_ => 2,
34+
})
35+
}
36+
37+
pub fn parse_diagnostics_output<T>(output: String, uri: &Path, vendor_querier: &T) -> HashMap<Url, Vec<Diagnostic>>
38+
where
39+
T: opengl::ShaderValidator + ?Sized,
40+
{
41+
let output_lines = output.split('\n');
42+
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(output_lines.count());
43+
let output_lines = output.split('\n');
44+
45+
for line in output_lines {
46+
let diagnostic_capture = match diagnostics_regex(vendor_querier).captures(line) {
47+
Some(d) => d,
48+
None => continue,
49+
};
50+
51+
// info!("match {:?}", diagnostic_capture);
52+
53+
let msg = diagnostic_capture.name("output").unwrap().as_str();
54+
55+
let line = match diagnostic_capture.name("linenum") {
56+
Some(c) => c.as_str().parse::<u32>().unwrap_or(0),
57+
None => 0,
58+
} - line_number_offset(vendor_querier);
59+
60+
// TODO: line matching maybe
61+
/* let line_text = source_lines[line as usize];
62+
let leading_whitespace = line_text.len() - line_text.trim_start().len(); */
63+
64+
let severity = match diagnostic_capture.name("severity") {
65+
Some(c) => match c.as_str().to_lowercase().as_str() {
66+
"error" => DiagnosticSeverity::Error,
67+
"warning" => DiagnosticSeverity::Warning,
68+
_ => DiagnosticSeverity::Information,
69+
},
70+
_ => DiagnosticSeverity::Information,
71+
};
72+
73+
let origin = match diagnostic_capture.name("filepath") {
74+
Some(o) => {
75+
if o.as_str() == "0" {
76+
uri.to_str().unwrap().to_string()
77+
} else {
78+
o.as_str().to_string()
79+
}
80+
}
81+
None => uri.to_str().unwrap().to_string(),
82+
};
83+
84+
let diagnostic = Diagnostic {
85+
range: Range::new(
86+
/* Position::new(line, leading_whitespace as u64),
87+
Position::new(line, line_text.len() as u64) */
88+
Position::new(line, 0),
89+
Position::new(line, 1000),
90+
),
91+
code: None,
92+
severity: Some(severity),
93+
source: Some(consts::SOURCE.into()),
94+
message: msg.trim().into(),
95+
related_information: None,
96+
tags: None,
97+
code_description: Option::None,
98+
data: Option::None,
99+
};
100+
101+
let origin_url = Url::from_file_path(origin).unwrap();
102+
match diagnostics.get_mut(&origin_url) {
103+
Some(d) => d.push(diagnostic),
104+
None => {
105+
diagnostics.insert(origin_url, vec![diagnostic]);
106+
}
107+
};
108+
}
109+
diagnostics
110+
}

server/src/main.rs

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use regex::Regex;
3939
use lazy_static::lazy_static;
4040

4141
mod commands;
42+
mod diagnostics_parser;
4243
mod configuration;
4344
mod consts;
4445
mod dfs;
@@ -53,7 +54,6 @@ mod url_norm;
5354
mod test;
5455

5556
lazy_static! {
56-
static ref RE_DIAGNOSTIC: Regex = Regex::new(r#"^(?P<filepath>[^?<>*|"]+)\((?P<linenum>\d+)\) : (?P<severity>error|warning) [A-C]\d+: (?P<output>.+)"#).unwrap();
5757
static ref RE_VERSION: Regex = Regex::new(r#"#version [\d]{3}"#).unwrap();
5858
static ref RE_INCLUDE: Regex = Regex::new(r#"^(?:\s)*?(?:#include) "(.+)"\r?"#).unwrap();
5959
static ref RE_INCLUDE_EXTENSION: Regex = Regex::new(r#"#extension GL_GOOGLE_include_directive ?: ?require"#).unwrap();
@@ -352,7 +352,7 @@ impl MinecraftShaderLanguageServer {
352352
return Ok(diagnostics);
353353
}
354354
};
355-
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
355+
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
356356
} else {
357357
let mut all_trees: Vec<(TreeType, Vec<(NodeIndex, Option<_>)>)> = Vec::new();
358358

@@ -402,86 +402,14 @@ impl MinecraftShaderLanguageServer {
402402
Some(s) => s,
403403
None => continue,
404404
};
405-
diagnostics.extend(self.parse_validator_stdout(uri, stdout, ""));
405+
diagnostics.extend(diagnostics_parser::parse_diagnostics_output(stdout, uri, self.opengl_context.as_ref()));
406406
}
407407
};
408408

409409
back_fill(&all_sources, &mut diagnostics);
410410
Ok(diagnostics)
411411
}
412412

413-
fn parse_validator_stdout(&self, uri: &Path, stdout: String, _source: &str) -> HashMap<Url, Vec<Diagnostic>> {
414-
let stdout_lines = stdout.split('\n');
415-
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = HashMap::with_capacity(stdout_lines.count());
416-
let stdout_lines = stdout.split('\n');
417-
418-
for line in stdout_lines {
419-
let diagnostic_capture = match RE_DIAGNOSTIC.captures(line) {
420-
Some(d) => d,
421-
None => continue
422-
};
423-
424-
eprintln!("match {:?}", diagnostic_capture);
425-
426-
let msg = diagnostic_capture.name("output").unwrap().as_str();
427-
428-
let line = match diagnostic_capture.name("linenum") {
429-
Some(c) => c.as_str().parse::<u32>().unwrap_or(0),
430-
None => 0,
431-
} - 2;
432-
433-
// TODO: line matching maybe
434-
/* let line_text = source_lines[line as usize];
435-
let leading_whitespace = line_text.len() - line_text.trim_start().len(); */
436-
437-
let severity = match diagnostic_capture.name("severity") {
438-
Some(c) => match c.as_str() {
439-
"error" => DiagnosticSeverity::Error,
440-
"warning" => DiagnosticSeverity::Warning,
441-
_ => DiagnosticSeverity::Information,
442-
}
443-
_ => DiagnosticSeverity::Information,
444-
};
445-
446-
let origin = match diagnostic_capture.name("filepath") {
447-
Some(o) => {
448-
if o.as_str() == "0" {
449-
uri.to_str().unwrap().to_string()
450-
} else {
451-
o.as_str().to_string()
452-
}
453-
},
454-
None => uri.to_str().unwrap().to_string(),
455-
};
456-
457-
let diagnostic = Diagnostic {
458-
range: Range::new(
459-
/* Position::new(line, leading_whitespace as u64),
460-
Position::new(line, line_text.len() as u64) */
461-
Position::new(line, 0),
462-
Position::new(line, 1000),
463-
),
464-
code: None,
465-
severity: Some(severity),
466-
source: Some(consts::SOURCE.into()),
467-
message: msg.trim().into(),
468-
related_information: None,
469-
tags: None,
470-
code_description: Option::None,
471-
data: Option::None,
472-
};
473-
474-
let origin_url = Url::from_file_path(origin).unwrap();
475-
match diagnostics.get_mut(&origin_url) {
476-
Some(d) => d.push(diagnostic),
477-
None => {
478-
diagnostics.insert(origin_url, vec![diagnostic]);
479-
},
480-
};
481-
}
482-
diagnostics
483-
}
484-
485413
pub fn get_dfs_for_node(&self, root: NodeIndex) -> Result<Vec<(NodeIndex, Option<NodeIndex>)>, dfs::error::CycleError> {
486414
let graph_ref = self.graph.borrow();
487415

server/src/opengl.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use mockall::automock;
99
#[cfg_attr(test, automock)]
1010
pub trait ShaderValidator {
1111
fn validate(&self, tree_type: super::TreeType, source: String) -> Option<String>;
12+
fn vendor(&self) -> String;
1213
}
1314

1415
pub struct OpenGlContext {
@@ -103,4 +104,8 @@ impl ShaderValidator for OpenGlContext {
103104

104105
result
105106
}
107+
108+
fn vendor(&self) -> String {
109+
unsafe { String::from_utf8(CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _).to_bytes().to_vec()).unwrap() }
110+
}
106111
}

server/src/test.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use std::io::Result;
66
use hamcrest2::prelude::*;
77
use pretty_assertions::assert_eq;
88

9-
use slog::Logger;
109
use slog::o;
10+
use slog::Logger;
1111
use tempdir::TempDir;
1212

1313
use petgraph::algo::is_cyclic_directed;
@@ -898,11 +898,12 @@ fn test_nvidia_diagnostics() {
898898

899899
let output = "/home/noah/.minecraft/shaderpacks/test/shaders/final.fsh(9) : error C0000: syntax error, unexpected '}', expecting ',' or ';' at token \"}\"";
900900

901-
let results = server.parse_validator_stdout(
902-
&PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(),
901+
let results = diagnostics_parser::parse_diagnostics_output(
903902
output.to_string(),
904-
"",
903+
&PathBuf::from_str("/home/noah/.minecraft/shaderpacks/test").unwrap(),
904+
server.opengl_context.as_ref(),
905905
);
906+
906907
assert_eq!(results.len(), 1);
907908
let first = results.into_iter().next().unwrap();
908909
assert_eq!(
@@ -923,7 +924,11 @@ ERROR: 0:10: '' : syntax error: #line
923924
ERROR: 0:15: 'varying' : syntax error: syntax error
924925
";
925926

926-
let results = server.parse_validator_stdout(&PathBuf::from_str("/home/test").unwrap(), output.to_string(), "");
927+
let results = diagnostics_parser::parse_diagnostics_output(
928+
output.to_string(),
929+
&PathBuf::from_str("/home/test").unwrap(),
930+
server.opengl_context.as_ref(),
931+
);
927932
assert_eq!(results.len(), 1);
928933
let first = results.into_iter().next().unwrap();
929934
assert_eq!(first.1.len(), 3);

0 commit comments

Comments
 (0)