From e56d182e3cb7e44a1be5f2aadd8546db797c5e5c Mon Sep 17 00:00:00 2001 From: Noah Santschi-Cooney Date: Sat, 8 Aug 2020 19:40:11 +0100 Subject: [PATCH] cpp style #line and diagnostics per-file per lint --- server/src/consts.rs | 6 ++ server/src/dfs.rs | 73 ++++++++++++------- server/src/graph.rs | 22 +++--- server/src/main.rs | 108 +++++++++++++++-------------- server/src/merge_views.rs | 69 +++++++++++------- server/src/test.rs | 104 ++++++++++++++++++++++++--- server/testdata/01/final.fsh.merge | 6 +- server/testdata/02/final.fsh.merge | 14 ++-- server/testdata/03/final.fsh.merge | 14 ++-- 9 files changed, 278 insertions(+), 138 deletions(-) create mode 100644 server/src/consts.rs diff --git a/server/src/consts.rs b/server/src/consts.rs new file mode 100644 index 0000000..2d38b9d --- /dev/null +++ b/server/src/consts.rs @@ -0,0 +1,6 @@ +pub static SOURCE: &str = "mc-glsl"; + +#[allow(dead_code)] +pub static INCLUDE_DIRECTIVE: &str = "#extension GL_GOOGLE_include_directive : require\n"; + +pub static CPP_LINE_DIRECTIVE: &str = "#extension GL_GOOGLE_cpp_style_line_directive : require\n"; \ No newline at end of file diff --git a/server/src/dfs.rs b/server/src/dfs.rs index a42b7ad..1e80ab8 100644 --- a/server/src/dfs.rs +++ b/server/src/dfs.rs @@ -1,11 +1,8 @@ use petgraph::stable_graph::NodeIndex; -use thiserror::Error; - use crate::graph::CachedStableGraph; use anyhow::{Result, Error}; -use std::fmt::{Debug, Display}; struct VisitCount { node: NodeIndex, @@ -47,7 +44,7 @@ impl <'a> Dfs<'a> { let cycle_nodes: Vec = self.cycle.iter().map(|n| n.node).collect(); return Err( Error::new( - CycleError::new(&cycle_nodes, *child, self.graph) + error::CycleError::new(&cycle_nodes, *child, self.graph) ) ); } @@ -103,31 +100,57 @@ impl <'a> Iterator for Dfs<'a> { } } -#[derive(Debug, Error)] -pub struct CycleError(Vec); +pub mod error { + use petgraph::stable_graph::NodeIndex; -impl CycleError { - fn new(nodes: &[NodeIndex], current_node: NodeIndex, graph: &CachedStableGraph) -> Self { - let mut resolved_nodes: Vec = nodes.iter().map(|i| graph.get_node(*i).clone()).collect(); - resolved_nodes.push(graph.get_node(current_node).clone()); - CycleError(resolved_nodes) - } -} + use thiserror::Error; -impl Display for CycleError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut disp = String::new(); - disp.push_str(format!("Include cycle detected:\n{} imports ", self.0[0]).as_str()); - for p in &self.0[1..self.0.len()-1] { - disp.push_str(format!("\n{}, which imports ", *p).as_str()); + use std::fmt::{Debug, Display}; + + use crate::{graph::CachedStableGraph, consts}; + + use rust_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range}; + + #[derive(Debug, Error)] + pub struct CycleError(Vec); + + impl CycleError { + pub fn new(nodes: &[NodeIndex], current_node: NodeIndex, graph: &CachedStableGraph) -> Self { + let mut resolved_nodes: Vec = nodes.iter().map(|i| graph.get_node(*i).clone()).collect(); + resolved_nodes.push(graph.get_node(current_node).clone()); + CycleError(resolved_nodes) + } + } + + impl Display for CycleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut disp = String::new(); + disp.push_str(format!("Include cycle detected:\n{} imports ", self.0[0]).as_str()); + for p in &self.0[1..self.0.len()-1] { + disp.push_str(format!("\n{}, which imports ", *p).as_str()); + } + disp.push_str(format!("\n{}", self.0[self.0.len()-1]).as_str()); + f.write_str(disp.as_str()) } - disp.push_str(format!("\n{}", self.0[self.0.len()-1]).as_str()); - f.write_str(disp.as_str()) } -} -impl Into for CycleError { - fn into(self) -> String { - format!("{}", self) + impl Into for CycleError { + fn into(self) -> Diagnostic { + Diagnostic{ + severity: Some(DiagnosticSeverity::Error), + range: Range::new(Position::new(0, 0), Position::new(0, 500)), + source: Some(consts::SOURCE.into()), + message: self.into(), + code: None, + tags: None, + related_information: None, + } + } + } + + impl Into for CycleError { + fn into(self) -> String { + format!("{}", self) + } } } \ No newline at end of file diff --git a/server/src/graph.rs b/server/src/graph.rs index 49c6647..bb0c01f 100644 --- a/server/src/graph.rs +++ b/server/src/graph.rs @@ -4,7 +4,6 @@ use petgraph::Direction; use petgraph::stable_graph::EdgeIndex; use std::collections::{HashMap, HashSet}; -use std::rc::Rc; use super::IncludePosition; @@ -34,16 +33,15 @@ impl CachedStableGraph { /// and caches the result in the `HashMap`. Complexity is **O(1)** if the value /// is cached (which should always be the case), else **O(n)** where **n** is /// the number of node indices, as an exhaustive search must be done. - pub fn find_node(&mut self, name: impl Into) -> Option { - let name_str = name.into(); - match self.cache.get(&name_str) { + pub fn find_node(&mut self, name: &str) -> Option { + match self.cache.get(name) { Some(n) => Some(*n), None => { // If the string is not in cache, O(n) search the graph (i know...) and then cache the NodeIndex // for later - let n = self.graph.node_indices().find(|n| self.graph[*n] == name_str); + let n = self.graph.node_indices().find(|n| self.graph[*n] == name); if let Some(n) = n { - self.cache.insert(name_str, n); + self.cache.insert(name.to_string(), n); } n } @@ -58,15 +56,16 @@ impl CachedStableGraph { self.graph.edge_weight(self.graph.find_edge(parent, child).unwrap()).unwrap() } - pub fn remove_node(&mut self, name: impl Into) { - let idx = self.cache.remove(&name.into()); + #[allow(dead_code)] + pub fn remove_node(&mut self, name: &str) { + let idx = self.cache.remove(name); if let Some(idx) = idx { self.graph.remove_node(idx); } } - pub fn add_node(&mut self, name: impl Into) -> NodeIndex { - let name_str = name.into(); + pub fn add_node(&mut self, name: &str) -> NodeIndex { + let name_str = name.to_string(); let idx = self.graph.add_node(name_str.clone()); self.cache.insert(name_str.clone(), idx); self.reverse_index.insert(idx, name_str); @@ -78,10 +77,12 @@ impl CachedStableGraph { self.graph.add_edge(parent, child, IncludePosition{filepath: child_path, line, start, end}) } + #[allow(dead_code)] pub fn edge_weights(&self, node: NodeIndex) -> Vec { self.graph.edges(node).map(|e| e.weight().clone()).collect() } + #[allow(dead_code)] pub fn child_node_names(&self, node: NodeIndex) -> Vec { self.graph.neighbors(node).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect() } @@ -90,6 +91,7 @@ impl CachedStableGraph { self.graph.neighbors(node).collect() } + #[allow(dead_code)] pub fn parent_node_names(&self, node: NodeIndex) -> Vec { self.graph.neighbors_directed(node, Direction::Incoming).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect() } diff --git a/server/src/main.rs b/server/src/main.rs index 3d56512..35b5beb 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -13,6 +13,7 @@ use std::cell::RefCell; use std::collections::{HashMap, LinkedList}; use std::convert::TryFrom; use std::fmt::{Display, Formatter}; +use std::cmp::max; use std::io::{stdin, stdout, BufRead, BufReader, Write}; use std::ops::Add; use std::process; @@ -35,6 +36,7 @@ mod provider; mod lsp_ext; mod dfs; mod merge_views; +mod consts; #[cfg(test)] mod test; @@ -46,7 +48,6 @@ lazy_static! { static ref RE_INCLUDE_EXTENSION: Regex = Regex::new(r#"#extension GL_GOOGLE_include_directive ?: ?require"#).unwrap(); } -static SOURCE: &str = "mc-glsl"; fn main() { let stdin = stdin(); @@ -105,7 +106,7 @@ pub struct IncludePosition { impl Display for IncludePosition { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - write!(f, "{{{}, l {}, s, {}, e {}}}", self.filepath, self.line, self.start, self.end) + write!(f, "{{path: '{}', line: {}}}", self.filepath, self.line) } } @@ -161,7 +162,7 @@ impl MinecraftShaderLanguageServer { for path in file_iter { let includes = self.find_includes(root, path.as_str()); - let idx = self.graph.borrow_mut().add_node(path.clone()); + let idx = self.graph.borrow_mut().add_node(&path); //eprintln!("adding {} with\n{:?}", path.clone(), includes); @@ -231,7 +232,7 @@ impl MinecraftShaderLanguageServer { includes } - pub fn lint(&self, uri: &str) -> Result> { + pub fn lint(&self, uri: &str) -> Result>> { // get all top level ancestors of this file let file_ancestors = match self.get_file_toplevel_ancestors(uri) { Ok(opt) => match opt { @@ -240,12 +241,11 @@ impl MinecraftShaderLanguageServer { }, Err(e) => return Err(e), }; - - let mut all_sources: HashMap = HashMap::new(); - + eprintln!("ancestors for {}:\n{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::>()); - - let mut diagnostics = Vec::new(); + + let mut all_sources: HashMap = HashMap::new(); + let mut diagnostics: HashMap> = HashMap::new();//Vec::new(); if file_ancestors.is_empty() { let root = self.graph.borrow_mut().find_node(uri).unwrap(); @@ -253,16 +253,9 @@ impl MinecraftShaderLanguageServer { let tree = match self.get_dfs_for_node(root) { Ok(tree) => tree, Err(e) => { - let e = e.downcast::().unwrap(); - return Ok(vec![Diagnostic{ - severity: Some(DiagnosticSeverity::Error), - range: Range::new(Position::new(0, 0), Position::new(0, 500)), - source: Some(SOURCE.into()), - message: e.into(), - code: None, - tags: None, - related_information: None, - }]) + let e = e.downcast::().unwrap(); + diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]); + return Ok(diagnostics); } }; @@ -284,22 +277,17 @@ impl MinecraftShaderLanguageServer { let nodes = match self.get_dfs_for_node(*root) { Ok(nodes) => nodes, Err(e) => { - let e = e.downcast::().unwrap(); - return Ok(vec![Diagnostic{ - severity: Some(DiagnosticSeverity::Error), - range: Range::new(Position::new(0, 0), Position::new(0, 500)), - source: Some(SOURCE.into()), - message: e.into(), - code: None, - tags: None, - related_information: None, - }]) + let e = e.downcast::().unwrap(); + diagnostics.insert(Url::from_file_path(uri).unwrap(), vec![e.into()]); + return Ok(diagnostics); } }; let sources = self.load_sources(&nodes)?; all_trees.push(nodes); all_sources.extend(sources); } + + //self.graph.borrow(). for tree in all_trees { let graph = self.graph.borrow(); @@ -314,16 +302,22 @@ impl MinecraftShaderLanguageServer { } }; + for (path, _) in all_sources { + diagnostics.entry(Url::from_file_path(path).unwrap()).or_default(); + } + Ok(diagnostics) } - fn parse_validator_stdout(&self, stdout: &str, source: &str) -> Vec { - let mut diagnostics: Vec = vec![]; - let source_lines: Vec<&str> = source.split('\n').collect(); - stdout.split('\n').for_each(|line| { + fn parse_validator_stdout(&self, stdout: &str, source: &str) -> HashMap> { + let stdout_lines = stdout.split('\n'); + let mut diagnostics: HashMap> = HashMap::with_capacity(stdout_lines.count()); + let stdout_lines = stdout.split('\n'); + + for line in stdout_lines { let diagnostic_capture = match RE_DIAGNOSTIC.captures(line) { Some(d) => d, - None => return + None => continue }; eprintln!("match {:?}", diagnostic_capture); @@ -331,16 +325,16 @@ impl MinecraftShaderLanguageServer { let msg = diagnostic_capture.get(4).unwrap().as_str().trim(); if msg.starts_with("compilation terminated") { - return + continue; } - let line = match diagnostic_capture.get(3) { + let line = max(match diagnostic_capture.get(3) { Some(c) => match c.as_str().parse::() { Ok(i) => i, Err(_) => 0, }, None => 0, - } - 1; + }, 2) - 2; // TODO: line matching maybe /* let line_text = source_lines[line as usize]; @@ -355,6 +349,10 @@ impl MinecraftShaderLanguageServer { _ => DiagnosticSeverity::Information, }; + let origin = match diagnostic_capture.get(2) { + Some(o) => o.as_str().to_string(), + None => "".to_string(), + }; let diagnostic = Diagnostic { range: Range::new( @@ -365,14 +363,20 @@ impl MinecraftShaderLanguageServer { ), code: None, severity: Some(severity), - source: Some(SOURCE.into()), + source: Some(consts::SOURCE.into()), message: msg.into(), related_information: None, tags: None, }; - diagnostics.push(diagnostic); - }); + let origin_url = Url::from_file_path(origin).unwrap(); + match diagnostics.get_mut(&origin_url) {//.get_or_insert(Vec::new()); + Some(d) => d.push(diagnostic), + None => { + diagnostics.insert(origin_url, vec![diagnostic]); + }, + }; + } diagnostics } @@ -415,15 +419,12 @@ impl MinecraftShaderLanguageServer { } fn invoke_validator(&self, source: LinkedList<&str>) -> Result { - eprintln!("validator bin path: {}", self.config.glslang_validator_path); let cmd = process::Command::new(&self.config.glslang_validator_path) .args(&["--stdin", "-S", "frag"]) .stdin(process::Stdio::piped()) .stdout(process::Stdio::piped()) .spawn(); - eprintln!("invoking validator"); - let mut child = cmd?;//.expect("glslangValidator failed to spawn"); let stdin = child.stdin.as_mut().expect("no stdin handle found"); @@ -441,12 +442,15 @@ impl MinecraftShaderLanguageServer { Ok(stdout) } - pub fn publish_diagnostic(&self, diagnostics: Vec, uri: impl Into, document_version: Option) { - self.endpoint.send_notification(PublishDiagnostics::METHOD, PublishDiagnosticsParams { - uri: uri.into(), - diagnostics, - version: document_version, - }).expect("failed to publish diagnostics"); + pub fn publish_diagnostic(&self, diagnostics: HashMap>, document_version: Option) { + eprintln!("DIAGNOSTICS:\n{:?}", diagnostics); + for (uri, diagnostics) in diagnostics { + self.endpoint.send_notification(PublishDiagnostics::METHOD, PublishDiagnosticsParams { + uri, + diagnostics, + version: document_version, + }).expect("failed to publish diagnostics"); + } } fn set_status(&self, status: impl Into, message: impl Into, icon: impl Into) { @@ -551,7 +555,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer { fn did_open_text_document(&mut self, params: DidOpenTextDocumentParams) { eprintln!("opened doc {}", params.text_document.uri); match self.lint(params.text_document.uri.path()/* , params.text_document.text */) { - Ok(diagnostics) => self.publish_diagnostic(diagnostics, params.text_document.uri, None), + Ok(diagnostics) => self.publish_diagnostic(diagnostics, None), Err(e) => eprintln!("error linting: {}", e), } } @@ -573,7 +577,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer { /*let file_content = fs::read(path).unwrap(); */ match self.lint(path.as_str()/* , String::from_utf8(file_content).unwrap() */) { - Ok(diagnostics) => self.publish_diagnostic(diagnostics, params.text_document.uri, None), + Ok(diagnostics) => self.publish_diagnostic(diagnostics, None), Err(e) => eprintln!("error linting: {}", e), } } @@ -679,7 +683,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer { .to_str() .unwrap() .to_string(); - let node = match self.graph.borrow_mut().find_node(curr_doc) { + let node = match self.graph.borrow_mut().find_node(&curr_doc) { Some(n) => n, None => { completable.complete(Ok(vec![])); diff --git a/server/src/merge_views.rs b/server/src/merge_views.rs index 223fdcc..49bdb7f 100644 --- a/server/src/merge_views.rs +++ b/server/src/merge_views.rs @@ -6,12 +6,7 @@ use core::slice::Iter; use petgraph::stable_graph::NodeIndex; -use crate::graph::CachedStableGraph; - -#[allow(dead_code)] -static INCLUDE_DIRECTIVE: &str = "#extension GL_GOOGLE_include_directive : require"; -#[allow(dead_code)] -static CPP_LINE_DIRECTIVE: &str = "#extension GL_GOOGLE_cpp_style_line_directive : require"; +use crate::{graph::CachedStableGraph, consts}; pub struct MergeViewGenerator<'a> { sources: &'a mut HashMap, @@ -38,16 +33,31 @@ impl <'a> MergeViewGenerator<'a> { let first_path = self.graph.get_node(first).clone(); last_offset_set.insert(first_path.clone(), 0); + + self.add_line_directive_extension(&first_path, &mut merge_list, &mut last_offset_set); self.create_merge_views(nodes_iter, &mut merge_list, &mut last_offset_set); // now we add a view of the remainder of the root file let offset = *last_offset_set.get(&first_path).unwrap(); - merge_list.push_back(&self.sources.get(&first_path).unwrap().as_str()[offset..]); + merge_list.push_back(&self.sources.get(&first_path).unwrap()[offset..]); merge_list } + fn add_line_directive_extension(&'a self, root_path: &str, merge_list: &mut LinkedList<&'a str>, last_offset_set: &mut HashMap) { + let root_source = self.sources.get(root_path).unwrap(); + let (char_offset, _) = self.char_offset_for_line(1, root_source); + merge_list.push_back(&root_source[..char_offset]); + merge_list.push_back(&consts::CPP_LINE_DIRECTIVE[..]); + let line_directive = format!("#line 2 \"{}\"\n", root_path); + self.line_directives.borrow_mut().push(line_directive); + unsafe { + self.unsafe_get_and_insert(merge_list); + } + last_offset_set.insert(root_path.into(), char_offset); + } + fn create_merge_views( &'a self, mut nodes: Peekable)>>, @@ -66,19 +76,10 @@ impl <'a> MergeViewGenerator<'a> { let child_path = self.graph.get_node(child).clone(); let source = self.sources.get(&parent_path).unwrap(); - let mut char_for_line: usize = 0; - let mut char_following_line: usize = 0; - for (n, line) in source.as_str().lines().enumerate() { - if n == edge.line { - char_following_line += line.len()+1; - break; - } - char_for_line += line.len()+1; - char_following_line = char_for_line; - } + let (char_for_line, char_following_line) = self.char_offset_for_line(edge.line, source); let offset = *last_offset_set.insert(parent_path.clone(), char_following_line).get_or_insert(0); - merge_list.push_back(&source.as_str()[offset..char_for_line]); + merge_list.push_back(&source[offset..char_for_line]); self.add_opening_line_directive(&child_path, merge_list); match nodes.peek() { @@ -87,7 +88,7 @@ impl <'a> MergeViewGenerator<'a> { // if the next element is not a child of this element, we dump the rest of this elements source if next.1.unwrap() != child { let source = self.sources.get(&child_path).unwrap(); - merge_list.push_back(&source.as_str()[..]); + merge_list.push_back(&source[..]); // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line self.add_closing_line_directive(edge.line+2, &parent_path, merge_list); } @@ -97,7 +98,7 @@ impl <'a> MergeViewGenerator<'a> { let offset = *last_offset_set.get(&child_path).unwrap(); let source = self.sources.get(&child_path).unwrap(); if offset <= source.len() { - merge_list.push_back(&source.as_str()[offset..]); + merge_list.push_back(&source[offset..]); } // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line @@ -106,15 +107,31 @@ impl <'a> MergeViewGenerator<'a> { }, None => { let source = self.sources.get(&child_path).unwrap(); - merge_list.push_back(&source.as_str()[..]); + merge_list.push_back(&source[..]); // +2 because edge.line is 0 indexed but #line is 1 indexed and references the *following* line self.add_closing_line_directive(edge.line+2, &parent_path, merge_list); } } } + // returns the character offset + 1 of the end of line number `line` and the character + // offset + 1 for the end of the line after the previous one + fn char_offset_for_line(&self, line_num: usize, source: &str) -> (usize, usize) { + let mut char_for_line: usize = 0; + let mut char_following_line: usize = 0; + for (n, line) in source.lines().enumerate() { + if n == line_num { + char_following_line += line.len()+1; + break; + } + char_for_line += line.len()+1; + char_following_line = char_for_line; + } + (char_for_line, char_following_line) + } + fn add_opening_line_directive(&self, path: &str, merge_list: &mut LinkedList<&str>) { - let line_directive = format!("#line 1 {}\n", path); + let line_directive = format!("#line 1 \"{}\"\n", path); self.line_directives.borrow_mut().push(line_directive); unsafe { self.unsafe_get_and_insert(merge_list); @@ -126,12 +143,12 @@ impl <'a> MergeViewGenerator<'a> { // a #line directive let line_directive = if let Some(l) = merge_list.back() { if l.starts_with("\n#line") { - format!("#line {} {}\n", line, path) + format!("#line {} \"{}\"\n", line, path) } else { - format!("\n#line {} {}\n", line, path) + format!("\n#line {} \"{}\"\n", line, path) } } else { - format!("\n#line {} {}\n", line, path) + format!("\n#line {} \"{}\"\n", line, path) }; self.line_directives.borrow_mut().push(line_directive); @@ -143,6 +160,6 @@ impl <'a> MergeViewGenerator<'a> { unsafe fn unsafe_get_and_insert(&self, merge_list: &mut LinkedList<&str>) { // :^) let vec_ptr_offset = self.line_directives.borrow().as_ptr().add(self.line_directives.borrow().len()-1); - merge_list.push_back(&vec_ptr_offset.as_ref().unwrap().as_str()[..]); + merge_list.push_back(&vec_ptr_offset.as_ref().unwrap()[..]); } } \ No newline at end of file diff --git a/server/src/test.rs b/server/src/test.rs index f1532af..84bf0c4 100644 --- a/server/src/test.rs +++ b/server/src/test.rs @@ -208,12 +208,29 @@ fn test_collect_root_ancestors() { let idx0 = graph.add_node("0"); let idx1 = graph.add_node("1"); let idx2 = graph.add_node("2"); + let idx3 = graph.add_node("3"); graph.add_edge(idx0, idx1, 2, 0, 0); graph.add_edge(idx1, idx2, 3, 0, 0); + graph.add_edge(idx3, idx1, 4, 0, 0); + + // 0 3 + // |/ + // 1 + // | + // 2 let roots = graph.collect_root_ancestors(idx2); - assert_eq!(roots, vec![idx0]); + assert_eq!(roots, vec![idx3, idx0]); + + let roots = graph.collect_root_ancestors(idx1); + assert_eq!(roots, vec![idx3, idx0]); + + let roots = graph.collect_root_ancestors(idx0); + assert_eq!(roots, vec![]); + + let roots = graph.collect_root_ancestors(idx3); + assert_eq!(roots, vec![]); } { let mut graph = graph::CachedStableGraph::new(); @@ -227,8 +244,23 @@ fn test_collect_root_ancestors() { graph.add_edge(idx0, idx2, 3, 0, 0); graph.add_edge(idx1, idx3, 5, 0, 0); + // 0 + // / \ + // 1 2 + // / + // 3 + let roots = graph.collect_root_ancestors(idx3); assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx2); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx1); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx0); + assert_eq!(roots, vec![]); } { let mut graph = graph::CachedStableGraph::new(); @@ -242,8 +274,55 @@ fn test_collect_root_ancestors() { graph.add_edge(idx2, idx3, 3, 0, 0); graph.add_edge(idx1, idx3, 5, 0, 0); + // 0 + // | + // 1 + // \ + // 2 \ + // \ / + // 3 + let roots = graph.collect_root_ancestors(idx3); assert_eq!(roots, vec![idx0, idx2]); + + let roots = graph.collect_root_ancestors(idx2); + assert_eq!(roots, vec![]); + + let roots = graph.collect_root_ancestors(idx1); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx0); + assert_eq!(roots, vec![]); + } + { + let mut graph = graph::CachedStableGraph::new(); + + let idx0 = graph.add_node("0"); + let idx1 = graph.add_node("1"); + let idx2 = graph.add_node("2"); + let idx3 = graph.add_node("3"); + + graph.add_edge(idx0, idx1, 2, 0, 0); + graph.add_edge(idx1, idx2, 4, 0, 0); + graph.add_edge(idx1, idx3, 6, 0, 0); + + // 0 + // | + // 1 + // / \ + // 2 3 + + let roots = graph.collect_root_ancestors(idx3); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx2); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx1); + assert_eq!(roots, vec![idx0]); + + let roots = graph.collect_root_ancestors(idx0); + assert_eq!(roots, vec![]); } } @@ -408,8 +487,8 @@ fn test_generate_merge_list_01() { let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/01", &mut server); - let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh")); - let common_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "common.glsl")); + let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh")); + let common_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "common.glsl")); server.graph.borrow_mut().add_edge(final_idx, common_idx, 2, 0, 0); @@ -430,6 +509,7 @@ fn test_generate_merge_list_01() { let merge_file = tmp_path.clone() + "/shaders/final.fsh.merge"; let mut truth = String::from_utf8(fs::read::(merge_file).unwrap()).unwrap(); + truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1); truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/"+"common.glsl"), 1); truth = truth.replace("!!", &(tmp_path+"/shaders/"+"final.fsh")); @@ -444,10 +524,10 @@ fn test_generate_merge_list_02() { let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/02", &mut server); - let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh")); - let test_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "test.glsl")); - let burger_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "burger.glsl")); - let sample_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "sample.glsl")); + let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh")); + let test_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl")); + let burger_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl")); + let sample_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl")); server.graph.borrow_mut().add_edge(final_idx, sample_idx, 2, 0, 0); server.graph.borrow_mut().add_edge(sample_idx, burger_idx, 4, 0, 0); @@ -471,6 +551,7 @@ fn test_generate_merge_list_02() { let mut truth = String::from_utf8(fs::read::(merge_file).unwrap()).unwrap(); + truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1); for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] { let path = tmp_path.clone(); truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1); @@ -488,10 +569,10 @@ fn test_generate_merge_list_03() { let (_tmp_dir, tmp_path) = copy_to_and_set_root("./testdata/03", &mut server); - let final_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/{}", tmp_path, "final.fsh")); - let test_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "test.glsl")); - let burger_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "burger.glsl")); - let sample_idx = server.graph.borrow_mut().add_node(format!("{}/shaders/utils/{}", tmp_path, "sample.glsl")); + let final_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/{}", tmp_path, "final.fsh")); + let test_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "test.glsl")); + let burger_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "burger.glsl")); + let sample_idx = server.graph.borrow_mut().add_node(&format!("{}/shaders/utils/{}", tmp_path, "sample.glsl")); server.graph.borrow_mut().add_edge(final_idx, sample_idx, 2, 0, 0); server.graph.borrow_mut().add_edge(sample_idx, burger_idx, 4, 0, 0); @@ -515,6 +596,7 @@ fn test_generate_merge_list_03() { let mut truth = String::from_utf8(fs::read::(merge_file).unwrap()).unwrap(); + truth = truth.replacen("!!", &(tmp_path.clone()+"/shaders/final.fsh"), 1); for file in &["sample.glsl", "burger.glsl", "sample.glsl", "test.glsl", "sample.glsl"] { let path = tmp_path.clone(); truth = truth.replacen("!!", &format!("{}/shaders/utils/{}", path, file), 1); diff --git a/server/testdata/01/final.fsh.merge b/server/testdata/01/final.fsh.merge index 0e087d1..86dc530 100644 --- a/server/testdata/01/final.fsh.merge +++ b/server/testdata/01/final.fsh.merge @@ -1,10 +1,12 @@ #version 120 +#extension GL_GOOGLE_cpp_style_line_directive : require +#line 2 "!!" -#line 1 !! +#line 1 "!!" float test() { return 0.5; } -#line 4 !! +#line 4 "!!" void main() { gl_FragColor[0] = vec4(0.0); diff --git a/server/testdata/02/final.fsh.merge b/server/testdata/02/final.fsh.merge index 154e8df..ebdec6b 100644 --- a/server/testdata/02/final.fsh.merge +++ b/server/testdata/02/final.fsh.merge @@ -1,26 +1,28 @@ #version 120 +#extension GL_GOOGLE_cpp_style_line_directive : require +#line 2 "!!" -#line 1 !! +#line 1 "!!" int sample() { return 5; } -#line 1 !! +#line 1 "!!" void burger() { // sample text } -#line 6 !! +#line 6 "!!" -#line 1 !! +#line 1 "!!" float test() { return 3.0; } -#line 8 !! +#line 8 "!!" int sample_more() { return 5; } -#line 4 !! +#line 4 "!!" void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); diff --git a/server/testdata/03/final.fsh.merge b/server/testdata/03/final.fsh.merge index 2cf7cff..33e6aeb 100644 --- a/server/testdata/03/final.fsh.merge +++ b/server/testdata/03/final.fsh.merge @@ -1,22 +1,24 @@ #version 120 +#extension GL_GOOGLE_cpp_style_line_directive : require +#line 2 "!!" -#line 1 !! +#line 1 "!!" int sample() { return 5; } -#line 1 !! +#line 1 "!!" void burger() { // sample text } -#line 6 !! +#line 6 "!!" -#line 1 !! +#line 1 "!!" float test() { return 3.0; } -#line 8 !! -#line 4 !! +#line 8 "!!" +#line 4 "!!" void main() { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);