2022-03-11 18:14:01 -06:00
|
|
|
use std::{fs, io::Write, process::Command};
|
2022-03-06 09:04:48 -06:00
|
|
|
|
|
|
|
use clap::Parser as ArgParser;
|
2022-03-07 02:15:43 -06:00
|
|
|
|
2022-03-06 09:04:48 -06:00
|
|
|
use lexer::lex;
|
|
|
|
use parser::parse;
|
2022-03-11 17:35:14 -06:00
|
|
|
use diagnostic::Diagnostics;
|
2022-03-06 14:45:09 -06:00
|
|
|
use hir::ast_to_ir;
|
2022-03-07 02:15:43 -06:00
|
|
|
use codegen::cpp;
|
2022-03-06 09:04:48 -06:00
|
|
|
|
|
|
|
pub mod args;
|
|
|
|
use args::{Args, Options};
|
|
|
|
|
2022-03-11 18:14:01 -06:00
|
|
|
pub mod config;
|
|
|
|
|
2022-03-06 09:04:48 -06:00
|
|
|
pub mod util;
|
|
|
|
use crate::util::log;
|
|
|
|
|
|
|
|
fn main() {
|
2022-03-11 18:14:01 -06:00
|
|
|
let config_file = fs::read_to_string("./hades.toml");
|
|
|
|
let config: config::Config;
|
|
|
|
match config_file {
|
|
|
|
Ok(content) => {
|
|
|
|
let parsed = config::parse_config(&content);
|
|
|
|
match parsed {
|
|
|
|
Ok(c) => config = c,
|
|
|
|
Err(e) => {
|
|
|
|
log(2, format!("{}", e));
|
|
|
|
config = config::default_config();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
log(1, format!("Error reading config file: {}, using default config", e));
|
|
|
|
config = config::default_config();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-06 09:04:48 -06:00
|
|
|
let args = Args::parse();
|
|
|
|
match args.options {
|
|
|
|
Options::Compile {
|
|
|
|
input: file_name,
|
|
|
|
ast: _print_ast,
|
2022-03-07 03:48:36 -06:00
|
|
|
log: should_log,
|
|
|
|
output,
|
2022-03-06 09:04:48 -06:00
|
|
|
} => {
|
2022-03-07 03:48:36 -06:00
|
|
|
// Macro to only log if `should_log` is true
|
|
|
|
macro_rules! logif {
|
|
|
|
($level:expr, $msg:expr) => { if should_log { log($level, $msg); } };
|
|
|
|
}
|
|
|
|
|
2022-03-07 02:15:43 -06:00
|
|
|
// Start timer
|
|
|
|
let start = std::time::Instant::now();
|
|
|
|
|
|
|
|
// Get file contents
|
2022-03-07 03:48:36 -06:00
|
|
|
logif!(0, format!("Reading {}", &file_name.display()));
|
2022-03-06 09:04:48 -06:00
|
|
|
let src = fs::read_to_string(&file_name).expect("Failed to read file");
|
|
|
|
|
2022-03-07 02:15:43 -06:00
|
|
|
// Lex the file
|
2022-03-06 09:04:48 -06:00
|
|
|
let (tokens, lex_error) = lex(src.clone());
|
2022-03-06 09:50:23 -06:00
|
|
|
let (ast, parse_error) = parse(tokens.unwrap(), src.chars().count());
|
2022-03-06 09:04:48 -06:00
|
|
|
|
2022-03-11 17:35:14 -06:00
|
|
|
let mut diagnostics = Diagnostics::new();
|
|
|
|
for err in lex_error { diagnostics.add_lex_error(err); }
|
|
|
|
for err in parse_error { diagnostics.add_parse_error(err); }
|
2022-03-06 09:04:48 -06:00
|
|
|
|
2022-03-11 17:35:14 -06:00
|
|
|
if diagnostics.has_error() {
|
|
|
|
diagnostics.display(src);
|
|
|
|
logif!(0, "Epic parsing fail");
|
|
|
|
std::process::exit(1);
|
|
|
|
} else {
|
|
|
|
logif!(0, format!("Parsing took {}ms", start.elapsed().as_millis()));
|
|
|
|
}
|
2022-03-06 09:50:23 -06:00
|
|
|
|
|
|
|
match ast {
|
|
|
|
Some(ast) => {
|
2022-03-07 02:15:43 -06:00
|
|
|
// Convert the AST to HIR
|
2022-03-11 17:35:14 -06:00
|
|
|
let (ir, lowering_error) = ast_to_ir(ast);
|
|
|
|
for err in lowering_error { diagnostics.add_lowering_error(err); }
|
|
|
|
if diagnostics.has_error() {
|
|
|
|
diagnostics.display(src);
|
|
|
|
logif!(0, "Epic Lowering(HIR) fail");
|
|
|
|
std::process::exit(1);
|
|
|
|
} else {
|
|
|
|
logif!(0, format!("Lowering took {}ms", start.elapsed().as_millis()));
|
|
|
|
}
|
|
|
|
|
2022-03-07 02:15:43 -06:00
|
|
|
// Generate code
|
|
|
|
let mut codegen = cpp::Codegen::new();
|
|
|
|
codegen.gen(ir);
|
2022-03-07 03:48:36 -06:00
|
|
|
logif!(0, "Successfully generated code.");
|
2022-03-07 02:15:43 -06:00
|
|
|
|
|
|
|
// Write code to file
|
2022-03-07 03:48:36 -06:00
|
|
|
let output_path = match output {
|
|
|
|
Some(output) => output,
|
|
|
|
None => file_name.with_extension("cpp").file_name().unwrap().to_os_string().into(),
|
|
|
|
};
|
|
|
|
let mut file = fs::File::create(&output_path).expect("Failed to create file");
|
2022-03-07 02:15:43 -06:00
|
|
|
file.write_all(codegen.emitted.as_bytes()).expect("Failed to write to file");
|
|
|
|
|
|
|
|
// End timer
|
|
|
|
let duration = start.elapsed().as_millis();
|
2022-03-06 14:45:09 -06:00
|
|
|
|
2022-03-07 03:48:36 -06:00
|
|
|
logif!(0, format!("Compilation took {}ms", duration));
|
2022-03-11 18:14:01 -06:00
|
|
|
logif!(0, format!("Wrote output to `{}`", output_path.display()));
|
|
|
|
|
|
|
|
let compiler = &config.compiler.compiler;
|
|
|
|
Command::new(compiler)
|
|
|
|
.arg(&output_path)
|
|
|
|
.spawn()
|
|
|
|
.expect("Failed to run compiler");
|
2022-03-06 09:50:23 -06:00
|
|
|
},
|
2022-03-11 18:14:01 -06:00
|
|
|
None => { unreachable!(); }
|
2022-03-06 09:04:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|