pub mod ast; pub mod jit; pub mod parsing; pub mod typing; use clap::{Parser, Subcommand}; use crate::ast::Module; /// Experimental compiler for lila #[derive(Parser, Debug)] #[command(author = "Romain P. ")] #[command(version, about, long_about = None)] struct Cli { #[command(subcommand)] command: Commands, } #[derive(Subcommand, Debug)] enum Commands { Parse { /// Paths to the source files files: Vec, /// Dump the AST to stdout #[arg(long)] dump_ast: bool, }, TypeCheck { /// Paths to the source files files: Vec, /// Dump the AST to stdout #[arg(long)] dump_ast: bool, }, Compile { /// Paths to the source files files: Vec, /// Dump the CLIR to stdout #[arg(long)] dump_clir: bool, }, Run { /// Paths to the source files files: Vec, #[arg(long)] dump_clir: bool, }, } fn parse(files: &Vec) -> Vec { let paths = files.iter().map(std::path::Path::new); paths .map(|path| match parsing::parse_file(&path) { Ok(module) => module, Err(e) => panic!("Parsing error: {:#?}", e), }) .collect() } fn check(modules: &mut Vec) { while let Some(module) = modules.pop() { if let Err(e) = module.type_check() { eprintln!("{}", e); return; } } } fn main() { let cli = Cli::parse(); match &cli.command { Commands::Parse { files, dump_ast } => { let modules = parse(files); if *dump_ast { for module in &modules { println!("{:#?}", &module); } } println!("Parsing OK"); } Commands::TypeCheck { files, dump_ast } => { let mut modules = parse(files); check(&mut modules); if *dump_ast { for module in &modules { println!("{:#?}", &module); } } } Commands::Compile { files, dump_clir } | Commands::Run { files, dump_clir } => { let mut jit = jit::JIT::default(); jit.dump_clir = *dump_clir; for file in files { match jit.compile_file(file) { Err(e) => eprintln!("{}", e), Ok(code) => { println!("Compiled {}", file); if let Commands::Run { .. } = cli.command { let ret = unsafe { let code_fn: unsafe extern "sysv64" fn() -> i32 = std::mem::transmute(code); code_fn() }; println!("Main returned {}", ret); } } } } } } }