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
use log::{info, trace};

use crate::errors::*;
use crate::generator::generate::GenerationTables;
use crate::model::flow::Flow;

use super::checker;
use super::connector;
use super::gatherer;
use super::optimizer;

/// Take a hierarchical flow definition in memory and compile it, generating a manifest for execution
/// of the flow, including references to libraries required.
pub fn compile(flow: &Flow) -> Result<GenerationTables> {
    trace!("compile()");
    let mut tables = GenerationTables::new();

    info!("=== Compiler phase: Gathering");
    gatherer::gather_functions_and_connections(flow, &mut tables, 0);
    info!("=== Compiler phase: Collapsing connections");
    tables.collapsed_connections = connector::collapse_connections(&tables.connections);
    info!("=== Compiler phase: Optimizing");
    optimizer::optimize(&mut tables);
    info!("=== Compiler phase: Indexing");
    gatherer::index_functions(&mut tables.functions);
    info!("=== Compiler phase: Calculating routes tables");
    connector::create_routes_table(&mut tables);
    info!("=== Compiler phase: Checking connections");
    checker::check_connections(&mut tables)?;
    info!("=== Compiler phase: Checking processes");
    checker::check_function_inputs(&mut tables)?;
    info!("=== Compiler phase: Preparing functions connections");
    connector::prepare_function_connections(&mut tables)?;

    Ok(tables)
}

#[cfg(test)]
mod test {
    use crate::model::flow::Flow;
    use crate::model::function::Function;
    use crate::model::io::IO;
    use crate::model::name::HasName;
    use crate::model::name::Name;
    use crate::model::process_reference::ProcessReference;
    use crate::model::route::Route;

    use super::compile;

    /*
                                                                                Test for a function that is dead code. It has no connections to it or from it so will
                                                                                never run. So it should be removed by the optimizer and not fail at check stage.
                                                                            */
    #[test]
    fn dead_function() {
        let function = Function::new(Name::from("Stdout"),
                                     false,
                                     "lib://flowruntime/stdio/stdout.toml".to_owned(),
                                     Name::from("test-function"),
                                     Some(vec!(IO::new("String","/print"))),
                                     Some(vec!()), "lib://flowruntime/stdio/stdout.toml",
                                     Route::from("/print"),
                                     Some("lib://flowruntime/stdio/stdout.toml".to_string()),
                                     vec!(),
                                     0,
                                     0,
        );

        let function_ref = ProcessReference {
            alias: function.alias().to_owned(),
            source: "lib://flowruntime/stdio/stdout.toml".to_string(),
            initializations: None
        };

        let mut flow = Flow::default();
        flow.alias = Name::from("context");
        flow.name = Name::from("test-flow");
        flow.process_refs = Some(vec!(function_ref));

        let _tables = compile(&flow).unwrap();
    }
}