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
//! # The Official Floorplan Compiler Crate
//!
//! This module interfaces with the Haskell implementation of the
//! Floorplan compiler, providing official support for compiling
//! Floorplan specifications into Rust code directly from the
//! cargo toolchain.
//!
//! In order to use this crate, you must have the `flp` executable
//! on your `$PATH` when developing a Floorplan-based memory manager.
//!
//! In order to compile directly from the cargo toolchain, include a
//! `build.rs` in your project root similar to the following:
//! 
//! ```rust,ignore
//! extern crate flp_compiler as flpc;
//!
//! fn main() {
//!    flpc::Build::new()
//!        .src("src/heap/layout.flp")
//!        .dest("src/heap/layout.rs")
//!        .compile();
//! }
//! ```
//!
//! For information on acquiring the Floorplan compiler itself,
//! go see the [GitHub project here][github-project].
//!
//! [github-project]: https://github.com/RedlineResearch/floorplan
use std::process::*;
use std::io::Write;

/// A build configuration.
#[derive(Clone, Debug)]
pub struct Build {
    src: Option<String>,
    dest: Option<String>,
}

/// A very basic implementation of a binding to an external compiler, supporting
/// specification of input and output files.
impl Build {

    /// Construct a new build configuration with default values, which will fail to compile
    /// by default.
    pub fn new() -> Build {
        Build {
            src: None,
            dest: None,
        }
    }

    /// Set the source `.flp` to be compiled.
    pub fn src(&mut self, s: &str) -> &mut Build {
        self.src = Some(s.to_string());
        self
    }

    /// Set the destination `.rs` file to generate the output library into.
    pub fn dest(&mut self, d: &str) -> &mut Build {
        self.dest = Some(d.to_string());
        self
    }

    /// Run the compiler on the current build configuration, failing miserably on error.
    pub fn compile(&mut self) {
        if let Err(e) = self.try_compile() {
            fail(&e);
        }
    }

    /// Attempt to run the compiler on the current build configuration, politely
    /// returning an error message if the compiler fails.
    pub fn try_compile(&mut self) -> Result<(), String> {
        let src = self.src.clone().unwrap();
        let dest = self.dest.clone().unwrap();
        Command::new("flp")
                .args(&[src, dest])
                .output()
                .expect("Floorplan failed to run.");
        Ok(())
    }

}

fn fail(s: &str) -> ! {
    let _ = writeln!(std::io::stderr(), "\nError: {}\n\n", s);
    std::process::exit(1);
}