cpp style #line and diagnostics per-file per lint

This commit is contained in:
Noah Santschi-Cooney 2020-08-08 19:40:11 +01:00
parent c322abe9af
commit e56d182e3c
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
9 changed files with 278 additions and 138 deletions

6
server/src/consts.rs Normal file
View file

@ -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";

View file

@ -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<NodeIndex> = 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<String>);
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<String> = 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<String>);
impl CycleError {
pub fn new(nodes: &[NodeIndex], current_node: NodeIndex, graph: &CachedStableGraph) -> Self {
let mut resolved_nodes: Vec<String> = 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<String> for CycleError {
fn into(self) -> String {
format!("{}", self)
impl Into<Diagnostic> 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<String> for CycleError {
fn into(self) -> String {
format!("{}", self)
}
}
}

View file

@ -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<String>) -> Option<NodeIndex> {
let name_str = name.into();
match self.cache.get(&name_str) {
pub fn find_node(&mut self, name: &str) -> Option<NodeIndex> {
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<String>) {
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<String>) -> 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<IncludePosition> {
self.graph.edges(node).map(|e| e.weight().clone()).collect()
}
#[allow(dead_code)]
pub fn child_node_names(&self, node: NodeIndex) -> Vec<String> {
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<String> {
self.graph.neighbors_directed(node, Direction::Incoming).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
}

View file

@ -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<Vec<Diagnostic>> {
pub fn lint(&self, uri: &str) -> Result<HashMap<Url, Vec<Diagnostic>>> {
// 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<String, String> = HashMap::new();
eprintln!("ancestors for {}:\n{:?}", uri, file_ancestors.iter().map(|e| self.graph.borrow().graph.node_weight(*e).unwrap().clone()).collect::<Vec<String>>());
let mut diagnostics = Vec::new();
let mut all_sources: HashMap<String, String> = HashMap::new();
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = 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::<dfs::CycleError>().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::<dfs::error::CycleError>().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::<dfs::CycleError>().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::<dfs::error::CycleError>().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<Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = 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<Url, Vec<Diagnostic>> {
let stdout_lines = stdout.split('\n');
let mut diagnostics: HashMap<Url, Vec<Diagnostic>> = 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::<u64>() {
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<String> {
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<Diagnostic>, uri: impl Into<Url>, document_version: Option<i64>) {
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<Url, Vec<Diagnostic>>, document_version: Option<i64>) {
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<String>, message: impl Into<String>, icon: impl Into<String>) {
@ -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![]));

View file

@ -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<String, String>,
@ -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<String, usize>) {
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<Iter<(NodeIndex, Option<NodeIndex>)>>,
@ -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()[..]);
}
}

View file

@ -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::<String>(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::<String>(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::<String>(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);

View file

@ -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);

View file

@ -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);

View file

@ -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);