lmntalc 0.13.1

A compiler for the LMNtal language
Documentation
use std::{io, path::PathBuf};

use clap::Parser;
use lmntalc::{
    compiler::{CompileOptions, compile_file},
    report::Reporter,
    target::Target,
    tree_root,
};
use owo_colors::OwoColorize;

#[derive(Parser)]
#[command(name = "LMNtal Compiler")]
#[command(author, version, about, long_about = None)]
struct Cli {
    #[arg(short, long, default_value = "cpp", help = "Target language")]
    pub target: Target,

    #[arg(short, long, help = "Output file name")]
    pub output: Option<PathBuf>,

    #[arg(
        long,
        value_name = "dump ast",
        default_value = "false",
        help = "Dump AST"
    )]
    dump_ast: bool,

    #[arg(
        long,
        value_name = "show ir",
        default_value = "false",
        help = "Show compiled IR"
    )]
    show_ir: bool,

    #[arg(
        long,
        value_name = "parse only",
        default_value = "false",
        help = "Parse and analyze only, do not generate actual code. (Show AST and IR is still available)"
    )]
    parse_only: bool,

    #[arg(value_name = "FILE")]
    source: PathBuf,
}

fn main() -> io::Result<()> {
    let cli = Cli::parse();
    let compilation = compile_file(
        &cli.source,
        &CompileOptions {
            target: (!cli.parse_only).then_some(cli.target),
        },
    )?;

    compilation.report(compilation.source())?;

    if cli.dump_ast
        && let Some(ast) = compilation.ast()
    {
        match tree_root(ast) {
            Ok(tree) => println!("{}\n{}", "AST:".bold().underline(), tree),
            Err(error) => println!("{}", error),
        }
    }

    if cli.show_ir
        && let Some(ir) = compilation.ir()
    {
        println!("{}\n{}", "Compiled IR:".bold().underline(), ir);
    }

    if compilation.has_errors() || cli.parse_only {
        return Ok(());
    }

    let output_file_name = cli.output.unwrap_or_else(|| {
        let mut file_name = cli.source.clone();
        file_name.set_extension(cli.target.extension());
        file_name
    });

    if let Some(code) = compilation.code() {
        std::fs::write(&output_file_name, code)?;
    }

    Ok(())
}