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
use std::process::Command;
use std::path::PathBuf;
use std::fs;
use crate::{getvar, InitialOptions, CompileOptions};
use crate::engine::file::{FileOwner, SourceFile};
use crate::engine::fmt::{eprintln_err_vec, eprintln_err_loc_vec};
use crate::engine::parser::parse_lines;
use crate::engine::state::State;
use crate::engine::{il, codegen};
use lazy_static::lazy_static;
use std::io::Write;

lazy_static! {
    static ref COMPILE_DIR: PathBuf = dirs::data_dir().unwrap().join(getvar!("COMPILE_DIR_NAME"));
}

const TOML_PRELUDE: &str = "\
[package]
name=\"fct-bin\"
version=\"1.0.0\"
edition=\"2018\"
[dependencies]
num=\"0.3.0\"
";

pub fn compile(initial_options: InitialOptions, compile_options: CompileOptions) -> i32
{
    let InitialOptions {
        source_file: source_file_name,
        escape_filenames,
    } = initial_options;
    let CompileOptions {
        output_file: output_file_name,
        local_lib,
        silent,
    } = compile_options;
    let mut file_owner = FileOwner::init();
    match SourceFile::from_arg(source_file_name, escape_filenames, &mut file_owner) {
        Ok(source_file) => {
            file_owner.files_mut()[source_file].read();
            let mut ins_vec = vec![];
            let mut err_vec = vec![];
            let mut state = State::init();
            let mut lines = parse_lines(file_owner.files()[source_file].handle(), &file_owner);
            il::gen_lines(&mut ins_vec, &mut err_vec, &mut lines, &mut state, &file_owner);
            if err_vec.is_empty() {
                let code = codegen::gen_rust(ins_vec);
                fs::create_dir_all(&*COMPILE_DIR).unwrap();
                Command::new("cargo").current_dir(&*COMPILE_DIR).args(&["init", "--bin"]).output().unwrap();
                fs::write((*COMPILE_DIR).join("src").join("main.rs"), code).unwrap();
                let mut toml = fs::File::create((*COMPILE_DIR).join("Cargo.toml")).unwrap();
                toml.write_all(TOML_PRELUDE.as_bytes()).unwrap();
                match local_lib {
                    Some(local_library) => {
                        write!(toml, "fct={{path=\"{}\"}}\n", local_library).unwrap();
                    }
                    None => {
                        write!(toml, "fct=\"{}\"\n", env!("CARGO_PKG_VERSION")).unwrap();
                    }
                }
                toml.flush().unwrap();
                let mut com = Command::new("cargo");
                com.current_dir(&*COMPILE_DIR).args(&["build", "--release"]);
                if silent {
                    com.output().unwrap();
                } else {
                    com.spawn().unwrap().wait().unwrap();
                }
                if cfg!(windows) {
                    fs::copy(COMPILE_DIR.join("target").join("release").join("fct-bin.exe"), &output_file_name).ok();
                } else {
                    fs::copy(COMPILE_DIR.join("target").join("release").join("fct-bin"), &output_file_name).ok();
                }
            } else {
                eprintln_err_loc_vec(err_vec, &file_owner);
            }
        }
        source_file_result => {
            if let Err(err_vec) = source_file_result { eprintln_err_vec(err_vec, &file_owner) }
        }
    }
    0
}