protospec_build/
lib.rs

1#[macro_use]
2extern crate quote;
3
4#[macro_use]
5pub mod result;
6use std::{
7    io::Write,
8    path::PathBuf,
9    process::{Command, Stdio},
10};
11
12pub use result::*;
13
14pub mod tokenizer;
15pub use tokenizer::*;
16
17pub mod ast;
18pub use ast::*;
19
20pub mod asg;
21pub use asg::*;
22
23pub mod parser;
24pub use parser::*;
25
26pub mod semantics;
27pub use semantics::*;
28
29pub mod import;
30pub use import::*;
31
32pub mod compiler;
33pub use compiler::*;
34
35pub mod coder;
36
37pub mod prelude;
38pub use prelude::*;
39
40pub mod ffi;
41pub use ffi::*;
42
43#[derive(Clone)]
44pub struct Options {
45    pub format_output: bool,
46    pub enum_derives: Vec<String>,
47    pub struct_derives: Vec<String>,
48    pub include_async: bool,
49    pub use_anyhow: bool,
50    pub debug_mode: bool,
51}
52
53impl Default for Options {
54    fn default() -> Self {
55        Options {
56            format_output: true,
57            include_async: false,
58            debug_mode: false,
59            enum_derives: vec![
60                "Eq".to_string(),
61                "PartialEq".to_string(),
62                "Debug".to_string(),
63                "Clone".to_string(),
64                "Default".to_string(),
65            ],
66            struct_derives: vec![
67                "Eq".to_string(),
68                "PartialEq".to_string(),
69                "Debug".to_string(),
70                "Clone".to_string(),
71                "Default".to_string(),
72            ],
73            use_anyhow: false,
74        }
75    }
76}
77
78pub fn rustfmt(input: &str) -> String {
79    let mut proc = Command::new("rustfmt")
80        .arg("--edition")
81        .arg("2021")
82        .stdin(Stdio::piped())
83        .stdout(Stdio::piped())
84        .stderr(Stdio::inherit())
85        .spawn()
86        .expect("rustfmt failed");
87    let stdin = proc.stdin.as_mut().unwrap();
88    stdin.write_all(input.as_bytes()).unwrap();
89    String::from_utf8_lossy(&proc.wait_with_output().unwrap().stdout).to_string()
90}
91
92pub fn compile_spec(name: &str, spec: &str, options: &Options) -> AsgResult<()> {
93    let resolver = PreludeImportResolver(NullImportResolver);
94    let program =
95        asg::Program::from_ast(&parse(spec).map_err(|x| -> Error { x.into() })?, &resolver)?;
96    let compiler_options = CompileOptions {
97        enum_derives: options.enum_derives.clone(),
98        struct_derives: options.struct_derives.clone(),
99        include_async: options.include_async,
100        use_anyhow: options.use_anyhow,
101        debug_mode: options.debug_mode,
102    };
103    let compiled = compiler::compile_program(&program, &compiler_options);
104    let mut compiled = compiled.to_string();
105    if options.format_output {
106        compiled = rustfmt(&compiled);
107    }
108    let mut target: PathBuf = std::env::var("OUT_DIR")
109        .expect("OUT_DIR env var not set")
110        .into();
111    target.push(format!("{}.rs", name));
112    std::fs::write(target, compiled).expect("failed to write to target");
113    Ok(())
114}
115
116#[macro_export]
117macro_rules! include_spec {
118    ($package: tt) => {
119        include!(concat!(env!("OUT_DIR"), concat!("/", $package, ".rs")));
120    };
121}