lila/src/main.rs

146 lines
3.9 KiB
Rust

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. <rpqt@rpqt.fr>")]
#[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<String>,
/// Dump the AST to stdout
#[arg(long)]
dump_ast: bool,
},
Check {
/// Paths to the source files
files: Vec<String>,
/// Dump the AST to stdout
#[arg(long)]
dump_ast: bool,
},
Compile {
/// Paths to the source files
files: Vec<String>,
/// Dump the CLIR to stdout
#[arg(long)]
dump_clir: bool,
},
Run {
/// Paths to the source files
files: Vec<String>,
#[arg(long)]
dump_clir: bool,
},
}
fn parse(files: &[String]) -> Vec<Module> {
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<Module>, 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);
}
}
}
}
}
}
}