Fixed cycle path rewinding

This commit is contained in:
Noah Santschi-Cooney 2020-07-30 23:21:53 +01:00
parent 1250c81365
commit d80adf83a3
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
4 changed files with 122 additions and 21 deletions

View file

@ -4,7 +4,7 @@ watchtest:
RUST_BACKTRACE=0 cargo watch -x test -i Makefile
test:
RUST_LIB_BACKTRACE=0 cargo test
RUST_LIB_BACKTRACE=0 RUST_BACKTRACE=0 cargo test
build:
cargo build --release

View file

@ -7,11 +7,17 @@ use crate::graph::CachedStableGraph;
use anyhow::{Result, Error};
use std::fmt::{Debug, Display};
struct VisitCount {
node: NodeIndex,
touch: usize,
children: usize,
}
/// Performs a depth-first search with duplicates
pub struct Dfs<'a> {
stack: Vec<NodeIndex>,
graph: &'a CachedStableGraph,
cycle: Vec<NodeIndex>
cycle: Vec<VisitCount>
}
impl <'a> Dfs<'a> {
@ -24,9 +30,11 @@ impl <'a> Dfs<'a> {
}
fn reset_path_to_branch(&mut self) {
while let Some(par) = self.cycle.pop() {
if self.graph.graph.edges(par).count() > 0 {
while let Some(par) = self.cycle.last_mut() {
par.touch += 1;
if par.touch > par.children {
self.cycle.pop();
} else {
break;
}
}
@ -35,10 +43,11 @@ impl <'a> Dfs<'a> {
fn check_for_cycle(&self, children: &[NodeIndex]) -> Result<()> {
for prev in &self.cycle {
for child in children {
if *prev == *child {
if prev.node == *child {
let cycle_nodes: Vec<NodeIndex> = self.cycle.iter().map(|n| n.node).collect();
return Err(
Error::new(
CycleError::new(&self.cycle, *child, self.graph)
CycleError::new(&cycle_nodes, *child, self.graph)
)
);
}
@ -49,11 +58,20 @@ impl <'a> Dfs<'a> {
}
impl <'a> Iterator for Dfs<'a> {
type Item = Result<NodeIndex>;
type Item = Result<(NodeIndex, Option<NodeIndex>)>;
fn next(&mut self) -> Option<Result<(NodeIndex, Option<NodeIndex>)>> {
let parent = match self.cycle.last() {
Some(p) => Some(p.node),
None => None,
};
fn next(&mut self) -> Option<Result<NodeIndex>> {
if let Some(node) = self.stack.pop() {
self.cycle.push(node);
self.cycle.push(VisitCount{
node,
children: self.graph.graph.edges(node).count(),
touch: 1,
});
let mut children = self.graph.child_node_indexes(node);
@ -78,7 +96,8 @@ impl <'a> Iterator for Dfs<'a> {
} else {
self.reset_path_to_branch();
}
return Some(Ok(node));
return Some(Ok((node, parent)));
}
None
}
@ -97,7 +116,6 @@ impl CycleError {
impl Display for CycleError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
eprintln!("cycle path {:?}", self.0);
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] {
@ -112,5 +130,4 @@ impl Into<String> for CycleError {
fn into(self) -> String {
format!("{}", self)
}
}

View file

@ -14,6 +14,7 @@ use std::io::{stdin, stdout, BufRead, BufReader, Write};
use std::ops::Add;
use std::process;
use std::rc::Rc;
use std::fs;
use anyhow::Result;
@ -257,7 +258,6 @@ impl MinecraftShaderLanguageServer {
match self.generate_merge_list(root) {
Ok((sources, views)) => lists.push(views),
Err(e) => {
eprintln!("cycle detected");
let e = e.downcast::<dfs::CycleError>().unwrap();
return Ok(vec![Diagnostic{
severity: Some(DiagnosticSeverity::Error),
@ -350,7 +350,7 @@ impl MinecraftShaderLanguageServer {
Ok(Some(roots))
}
fn generate_merge_list(&self, root: NodeIndex) -> Result<(LinkedList<String>, LinkedList<&str>)> {
pub fn generate_merge_list(&self, root: NodeIndex) -> Result<(LinkedList<String>, LinkedList<&str>)> {
let mut merge_list = LinkedList::new();
// need to return all sources along with the views to appease the lifetime god
let mut all_sources = LinkedList::new();
@ -362,15 +362,16 @@ impl MinecraftShaderLanguageServer {
//let slice_stack = Vec::new();
let iteration_order: Vec<_> = dfs.collect::<Result<Vec<_>, _>>()?;
for n in dfs {
/* for n in dfs {
if n.is_err() {
return Err(n.err().unwrap());
}
/* let path = self.graph.borrow().get_node(n);
let file_content = String::from_utf8(std::fs::read(path).unwrap()); */
}
} */
/* let children = self.graph.borrow().child_node_indexes(root);
@ -530,7 +531,7 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
let path: String = percent_encoding::percent_decode_str(params.text_document.uri.path()).decode_utf8().unwrap().into();
let file_content = std::fs::read(path).unwrap();
let file_content = fs::read(path).unwrap();
match self.lint(params.text_document.uri.path(), String::from_utf8(file_content).unwrap()) {
Ok(diagnostics) => self.publish_diagnostic(diagnostics, params.text_document.uri, None),
Err(e) => eprintln!("error linting: {}", e),

View file

@ -203,6 +203,44 @@ fn test_collect_root_ancestors() {
#[test]
fn test_graph_dfs() {
{
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(idx0, idx2, 3, 0, 0);
graph.add_edge(idx1, idx3, 5, 0, 0);
let dfs = dfs::Dfs::new(&graph, idx0);
let mut collection = Vec::new();
for i in dfs {
assert_that!(&i, ok());
collection.push(i.unwrap());
}
let nodes: Vec<NodeIndex> = collection.iter().map(|n| n.0).collect();
let parents: Vec<Option<NodeIndex>> = collection.iter().map(|n| n.1).collect();
// 0
// / \
// 1 2
// /
// 3
let expected_nodes = vec![idx0, idx1, idx3, idx2];
assert_eq!(expected_nodes, nodes);
let expected_parents = vec![None, Some(idx0), Some(idx1), Some(idx0)];
assert_eq!(expected_parents, parents);
assert!(!is_cyclic_directed(&graph.graph));
}
{
let mut graph = graph::CachedStableGraph::new();
@ -233,7 +271,9 @@ fn test_graph_dfs() {
assert_that!(&i, ok());
collection.push(i.unwrap());
}
let nodes: Vec<NodeIndex> = collection.iter().map(|n| n.0).collect();
let parents: Vec<Option<NodeIndex>> = collection.iter().map(|n| n.1).collect();
// 0
// / \
// 1 2
@ -241,9 +281,13 @@ fn test_graph_dfs() {
// 3 4 5
// \ /
// 6 - 7
let expected = vec![idx0, idx1, idx3, idx6, idx7, idx4, idx6, idx7, idx2, idx5, idx4, idx6, idx7];
let expected_nodes = vec![idx0, idx1, idx3, idx6, idx7, idx4, idx6, idx7, idx2, idx5, idx4, idx6, idx7];
assert_eq!(expected, collection);
assert_eq!(expected_nodes, nodes);
let expected_parents = vec![None, Some(idx0), Some(idx1), Some(idx3), Some(idx6), Some(idx1), Some(idx4), Some(idx6), Some(idx0), Some(idx2), Some(idx2), Some(idx4), Some(idx6)];
assert_eq!(expected_parents, parents);
assert!(!is_cyclic_directed(&graph.graph));
}
@ -311,4 +355,43 @@ fn test_graph_dfs_cycle() {
println!("{:?}", dfs.next());
println!("{:?}", dfs.next());
}
}
#[test]
fn test_generate_merge_list() {
let mut server = new_temp_server();
let tmp_dir = TempDir::new("mcshader").unwrap();
fs::create_dir(tmp_dir.path().join("shaders")).unwrap();
copy_files("./testdata/01", &tmp_dir);
let tmp_path = tmp_dir.path().as_os_str().to_str().unwrap();
let tmp_uri = format!("{}{}/shaders", "file://", tmp_path);
server.root = Some(tmp_uri);
let final_idx = server.graph.borrow_mut().add_node(format!("{}/{}", tmp_path, "final.fsh"));
let common_idx = server.graph.borrow_mut().add_node(format!("{}/{}", tmp_path, "common.glsl"));
server.graph.borrow_mut().add_edge(final_idx, common_idx, 2, 0, 0);
let result = server.generate_merge_list(final_idx);
assert_that!(&result, ok());
let total: String = result
.unwrap().1
.iter()
.map(|s| &**s)
.collect::<Vec<&str>>()
.join("");
let merge_file = String::from(tmp_path) + "/shaders/final.fsh.merge";
let truth = String::from_utf8(fs::read::<String>(merge_file).unwrap()).unwrap();
assert_that!(total, eq(truth));
server.endpoint.request_shutdown();
}