-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
117 lines (106 loc) · 3.56 KB
/
main.rs
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::{env, fs, io};
use std::path::Path;
use std::process::{Command, exit, ExitStatus};
use latte::backend::compile;
use latte::frontend::CheckedProgram;
use latte::frontend::process_file;
/// get a single required command line argument
pub fn parse_arg() -> String {
let args: Vec<String> = env::args().collect();
match args.get(1) {
Some(input_filename) => {
String::from(input_filename)
}
None => {
println!("Usage: {} {}", &args[0], "[input_filename]");
exit(2)
}
}
}
/// get key from environment variable, or default if it's not defined
pub fn parse_env(key: &str, default: &str) -> String {
match env::var_os(key) {
Some(llvm_as) => llvm_as.into_string().unwrap(),
None => String::from(default),
}
}
/// checks exit status of an executed command
pub fn check_exit_code(command_name: &str, status: &io::Result<ExitStatus>) {
match status {
Ok(status) => {
if !status.success() {
eprintln!("{} exited with error code: {:?}", command_name, status);
exit(1);
}
}
Err(e) => {
eprintln!("{} failed to execute: {:?}", command_name, e);
exit(1);
}
};
}
/// compile llvm file (.ll) or exit with error
fn compile_llvm_file(program: CheckedProgram, output_path: &String) {
let compiled_code = compile(program);
match fs::write(output_path, compiled_code) {
Ok(_) => {}
Err(e) => {
eprintln!("Failed to write compulation output output to file {}: {:?}", output_path, e);
exit(1);
}
}
}
/// compile and link binary (.bc) file or exit with error
fn compile_binary_file(
llvm_assembler: &String, llvm_linker: &String, llvm_runtime: &String,
llvm_compiled_program: &String, binary_output_path: &String,
) {
let mut compilation_output_dir = env::temp_dir().to_path_buf();
compilation_output_dir.push("latte_program_out.bc");
let compilation_output_file = compilation_output_dir.to_str().unwrap();
let compilation_status = Command::new(llvm_assembler)
.arg("-o")
.arg(compilation_output_file)
.arg(llvm_compiled_program)
.status();
check_exit_code(llvm_assembler, &compilation_status);
let linking_status = Command::new(llvm_linker)
.arg("-o")
.arg(binary_output_path)
.arg(llvm_runtime)
.arg(compilation_output_file)
.status();
check_exit_code(llvm_linker, &linking_status);
}
fn main() {
let input_filename = parse_arg();
let llvm_assembler = parse_env("LLVM_ASSEMBLER", "llvm-as");
let llvm_linker = parse_env("LLVM_LINKER", "llvm-link");
let llvm_runtime = parse_env("LLVM_RUNTIME", "lib/runtime.bc");
let llvm_output_filename = String::from(
Path::new(&input_filename).with_extension("ll").to_str().unwrap()
);
let binary_output_filename = String::from(
Path::new(&input_filename).with_extension("bc").to_str().unwrap()
);
match process_file(input_filename) {
Ok(prog) => {
eprintln!("OK");
compile_llvm_file(prog, &llvm_output_filename);
compile_binary_file(
&llvm_assembler,
&llvm_linker,
&llvm_runtime,
&llvm_output_filename,
&binary_output_filename,
);
}
Err(err_vec) => {
eprintln!("ERROR");
for err in err_vec.iter() {
eprintln!("{}", err);
}
exit(1);
}
}
}