#![allow(clippy::wildcard_imports)] #![allow(clippy::too_many_lines)] mod constants; mod interpret; mod util; mod compile; mod parser; mod lexer; mod preprocessor; mod typechecker; mod precompiler; mod config; mod errors; use config::*; use std::{fs, collections::HashMap}; use clap::Parser; use color_eyre::Result; use eyre::eyre; #[derive(Parser, Debug, Clone)] #[command(author=env!("CARGO_PKG_AUTHORS"), version=env!("CARGO_PKG_VERSION"), about=env!("CARGO_PKG_DESCRIPTION"), long_about=env!("CARGO_PKG_DESCRIPTION"))] pub struct Args { /// Input source file #[arg(long, short)] in_file: String, /// Output compiled file #[arg(long, short, default_value_t=String::from(DEFAULT_OUT_FILE))] out_file: String, /// Compile #[arg(long, short)] compile: bool, /// Interpert #[arg(long, short='s')] interpret: bool, /// Run the compiled executable #[arg(long, short)] run: bool, /// Dont print any output exept the actual running codes output #[arg(long, short)] quiet: bool, /// Add an include directory [default: ["./include", "~/.mclang/include"]] #[arg(long, short='I')] include: Vec, /// Unsafe mode, disables typechecking #[arg(long="unsafe", default_value_t = false)] unsaf: bool, /// Optimisation level, available levels: 'D': debug, '0': No optimisations #[arg(long, short='O', default_value_t=String::from("0"))] optimisation: String, // disables the main function #[arg(long="lib")] lib_mode: bool //#[arg(long, short='F')] //features: Vec, } impl Args { /// Get optimisation level /// 0 => no optimisations /// 1 => slight optimisations, mostly size ones /// # Errors /// /// Throws when the opt level is not known pub fn get_opt_level(&self) -> Result{ match self.optimisation.as_str() { "D" | "d" => Ok(0), "0" | "" => Ok(1), o => { error!("Unknown optimisation level {o}"); Err(eyre!("")) } } } } fn main() -> Result<()>{ let args = Args::parse(); let Ok(code) = fs::read_to_string(&args.in_file) else { error!("Failed to read file {}, exiting!", &args.in_file); return Ok(()); }; let tokens = lexer::lex(&code, args.in_file.as_str(), &args); let mut parser = parser::Parser::new(tokens, &args, None); let tokens = match parser.parse(){ Ok(t) => t, Err(e) => { error!("Parsing failed, exiting!"); if crate::DEV_MODE { return Err(e) } return Ok(()); } }; match typechecker::typecheck(tokens.clone(), &args, None, HashMap::new(), HashMap::new()) { Ok(_) => (), Err(e) => { error!("Typechecking failed, exiting!"); if crate::DEV_MODE { return Err(e); } return Ok(()); } }; let c = if args.compile && args.interpret { error!("Cannot compile and interpret at the same time"); 0 } else if args.interpret { if let Ok(c) = interpret::linux_x86_64::run(&tokens) { c } else { error!("Interpretation failed, exiting!"); 1 } } else if args.compile { if let Ok(c) = compile::linux_x86_64::compile(&tokens, &args) { c } else { error!("Compilation failed, exiting!"); 1 } } else { error!("Did not choose to compile or to interpret, exiting"); 0 }; std::process::exit(c); }