pub mod ast; pub mod jit; pub mod parsing; pub mod source; pub mod typing; use std::default::Default; use std::path::PathBuf; use clap::{Parser as ClapParser, Subcommand}; use crate::ast::Module; use crate::parsing::Parser; use crate::source::SourceCache; /// Experimental compiler for lila #[derive(ClapParser, 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, }, Check { /// 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: &[String]) -> Vec { let mut parser = parsing::DefaultParser::default(); let paths = files.iter().map(std::path::Path::new); paths .enumerate() .map(|(i, path)| match parser.parse_file(path, i as u32) { Ok(module) => module, Err(e) => panic!("Parsing error: {:#?}", e), }) .collect() } fn check(modules: &mut Vec, source_cache: &mut SourceCache) { for module in modules { if let Err(errors) = module.type_check() { for error in errors { error .to_report(module) .eprint(&mut *source_cache) .expect("cannot write error to stderr"); } } } } 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::Check { files, dump_ast } => { let mut source_cache = SourceCache { paths: files.iter().map(PathBuf::from).collect(), file_cache: ariadne::FileCache::default(), }; let mut modules = parse(files); check(&mut modules, &mut source_cache); if *dump_ast { for module in &modules { println!("{:#?}", &module); } } } Commands::Compile { files, dump_clir } | Commands::Run { files, dump_clir } => { if files.is_empty() { println!("No input files"); return; } let mut source_cache = SourceCache { paths: files.iter().map(PathBuf::from).collect(), file_cache: ariadne::FileCache::default(), }; let mut jit = jit::JIT::default(); jit.dump_clir = *dump_clir; for (id, file) in files.iter().enumerate() { match jit.compile_file(file, id as u32, &mut source_cache) { 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); } } } } } } }