1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//  WORKFLOW OPTIMIZE.rs
//    by Lut99
//
//  Created:
//    19 Oct 2022, 11:19:39
//  Last edited:
//    23 Dec 2022, 16:36:20
//  Auto updated?
//    Yes
//
//  Description:
//!   Implements a traversal that optimizes a workflow by combining as
//!   much edges into one as possible.
//

use crate::ast_unresolved::UnresolvedWorkflow;
use crate::errors::AstError;


/***** TESTS *****/
#[cfg(test)]
mod tests {
    use brane_dsl::ParserOptions;
    use brane_shr::utilities::{create_data_index, create_package_index, test_on_dsl_files};
    use specifications::data::DataIndex;
    use specifications::package::PackageIndex;

    use super::super::print::ast_unresolved;
    use super::*;
    use crate::state::CompileState;
    use crate::{CompileResult, CompileStage, compile_snippet_to};


    /// Tests the traversal by generating symbol tables for every file.
    #[test]
    fn test_workflow_optimize() {
        test_on_dsl_files("BraneScript", |path, code| {
            // Start by the name to always know which file this is
            println!("{}", (0..80).map(|_| '-').collect::<String>());
            println!("File '{}' gave us:", path.display());

            // Load the package index
            let pindex: PackageIndex = create_package_index();
            let dindex: DataIndex = create_data_index();

            // First, compile but not resolve
            let mut state: CompileState = CompileState::new();
            let workflow: UnresolvedWorkflow =
                match compile_snippet_to(&mut state, code.as_bytes(), &pindex, &dindex, &ParserOptions::bscript(), CompileStage::Compile) {
                    CompileResult::Unresolved(wf, warns) => {
                        // Print warnings if any
                        for w in warns {
                            w.prettyprint(path.to_string_lossy(), &code);
                        }
                        wf
                    },
                    CompileResult::Eof(err) => {
                        // Print the error
                        err.prettyprint(path.to_string_lossy(), &code);
                        panic!("Failed to optimize workflow (see output above)");
                    },
                    CompileResult::Err(errs) => {
                        // Print the errors
                        for e in errs {
                            e.prettyprint(path.to_string_lossy(), &code);
                        }
                        panic!("Failed to optimize workflow (see output above)");
                    },

                    _ => {
                        unreachable!();
                    },
                };

            // Now print the file for prettyness
            ast_unresolved::do_traversal(&state, workflow, std::io::stdout()).unwrap();
            println!("{}\n\n", (0..40).map(|_| "- ").collect::<String>());

            // Run up to this traversal
            let mut state: CompileState = CompileState::new();
            let workflow: UnresolvedWorkflow = match compile_snippet_to(
                &mut state,
                code.as_bytes(),
                &pindex,
                &dindex,
                &ParserOptions::bscript(),
                CompileStage::WorkflowOptimization,
            ) {
                CompileResult::Unresolved(wf, warns) => {
                    // Print warnings if any
                    for w in warns {
                        w.prettyprint(path.to_string_lossy(), &code);
                    }
                    wf
                },
                CompileResult::Eof(err) => {
                    // Print the error
                    err.prettyprint(path.to_string_lossy(), &code);
                    panic!("Failed to optimize workflow (see output above)");
                },
                CompileResult::Err(errs) => {
                    // Print the errors
                    for e in errs {
                        e.prettyprint(path.to_string_lossy(), &code);
                    }
                    panic!("Failed to optimize workflow (see output above)");
                },

                _ => {
                    unreachable!();
                },
            };

            // Now print the file for prettyness
            ast_unresolved::do_traversal(&state, workflow, std::io::stdout()).unwrap();
            println!("{}\n\n", (0..80).map(|_| '-').collect::<String>());
        });
    }
}





/***** ARGUMENTS *****/
/// Optimizes the given UnresolvedWorkflow by collapsing successive linear edges into one edge.
///
/// # Arguments
/// - `root`: The root node of the tree on which this compiler pass will be done.
///
/// # Returns
/// The same UnresolvedWorkflow but now (hopefully) with less edges.
///
/// # Errors
/// This pass doesn't error, but might return one for convention purposes.
///
/// # Panics
/// This function may panic if any of the previous passes did not do its job, and the given UnresolvedWorkflow is ill-formed.
pub fn do_traversal(root: UnresolvedWorkflow) -> Result<UnresolvedWorkflow, Vec<AstError>> {
    let mut root: UnresolvedWorkflow = root;

    // Pass over each of the buffers
    root.main_edges.merge_linear();
    for edges in root.f_edges.values_mut() {
        edges.merge_linear();
    }

    // Done
    Ok(root)
}