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
#[macro_use]
extern crate quote;

#[macro_use]
pub mod result;
use std::{io::Write, path::PathBuf, process::{Command, Stdio}};

pub use result::*;

pub mod tokenizer;
pub use tokenizer::*;

pub mod ast;
pub use ast::*;

pub mod asg;
pub use asg::*;

pub mod parser;
pub use parser::*;

pub mod semantifier;
pub use semantifier::*;

pub mod import;
pub use import::*;

pub mod compiler;
pub use compiler::*;

// pub mod decoder;

pub mod coder;

pub mod prelude;
pub use prelude::*;

#[derive(Clone)]
pub struct Options {
    pub format_output: bool,
    pub derives: Vec<String>,
}

impl Default for Options {
    fn default() -> Self {
        Options {
            format_output: true,
            derives: vec![
                "PartialEq".to_string(),
                "Debug".to_string(),
                "Clone".to_string(),
            ],
        }
    }
}

pub fn rustfmt(input: &str) -> String {
    let mut proc = Command::new("rustfmt")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()
        .expect("rustfmt failed");
    let stdin = proc.stdin.as_mut().unwrap();
    stdin.write_all(input.as_bytes()).unwrap();
    String::from_utf8_lossy(&proc.wait_with_output().unwrap().stdout).to_string()
}

pub fn compile_spec(name: &str, spec: &str, options: &Options) -> AsgResult<()> {
    let resolver = PreludeImportResolver(NullImportResolver);
    let program = asg::Program::from_ast(
        &parse(spec).map_err(|x| -> Error { x.into() })?,
        &resolver,
    )?;
    let compiler_options = CompileOptions {
        derives: options.derives.clone(),
    };
    let compiled = compiler::compile_program(&program, &compiler_options);
    let mut compiled = compiled.to_string();
    if options.format_output {
        compiled = rustfmt(&compiled);
    }
    let mut target: PathBuf = std::env::var("OUT_DIR").expect("OUT_DIR env var not set").into();
    target.push(format!("{}.rs", name));
    std::fs::write(target, compiled).expect("failed to write to target");
    Ok(())
}

#[macro_export]
macro_rules! include_spec {
    ($package: tt) => {
        include!(concat!(env!("OUT_DIR"), concat!("/", $package, ".rs")));
    };
}