use std::path::PathBuf;
use std::process::ExitCode;
use clap::{Parser, Subcommand, ValueEnum};
use luna_core::version::LuaVersion;
use crate::embed::{AotError, compile_and_link, embed_bytecode};
#[derive(Parser, Debug)]
#[command(name = "luna-aot", version, about, long_about = None)]
pub struct Cli {
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Compile(CompileArgs),
}
#[derive(clap::Args, Debug)]
pub struct CompileArgs {
pub input: PathBuf,
#[arg(short = 'o', long = "out")]
pub out: Option<PathBuf>,
#[arg(long = "target")]
pub target: Option<String>,
#[arg(long = "dialect", default_value = "lua55")]
pub dialect: DialectArg,
#[arg(long = "scaffold-only", default_value_t = false)]
pub scaffold_only: bool,
}
#[derive(ValueEnum, Copy, Clone, Debug)]
#[clap(rename_all = "lower")]
pub enum DialectArg {
#[clap(name = "5.1", alias = "lua51")]
Lua51,
#[clap(name = "5.2", alias = "lua52")]
Lua52,
#[clap(name = "5.3", alias = "lua53")]
Lua53,
#[clap(name = "5.4", alias = "lua54")]
Lua54,
#[clap(name = "5.5", alias = "lua55")]
Lua55,
#[clap(name = "macrolua", alias = "macro")]
MacroLua,
}
impl From<DialectArg> for LuaVersion {
fn from(d: DialectArg) -> Self {
match d {
DialectArg::Lua51 => LuaVersion::Lua51,
DialectArg::Lua52 => LuaVersion::Lua52,
DialectArg::Lua53 => LuaVersion::Lua53,
DialectArg::Lua54 => LuaVersion::Lua54,
DialectArg::Lua55 => LuaVersion::Lua55,
DialectArg::MacroLua => LuaVersion::MacroLua,
}
}
}
pub fn run() -> ExitCode {
let cli = Cli::parse();
match cli.command {
Command::Compile(args) => match do_compile(args) {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("luna-aot: {e}");
ExitCode::FAILURE
}
},
}
}
fn do_compile(args: CompileArgs) -> Result<(), AotError> {
let out = args.out.unwrap_or_else(|| default_out_for(&args.input));
let version = args.dialect.into();
if args.scaffold_only {
embed_bytecode(&args.input, &out, args.target.as_deref(), version)
} else {
compile_and_link(&args.input, &out, args.target.as_deref(), version)
}
}
fn default_out_for(input: &std::path::Path) -> PathBuf {
let stem = input
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("a")
.to_string();
let mut p = input
.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| PathBuf::from("."));
p.push(stem);
p
}