tsar 0.3.0

Tsar programming language
Documentation
use crate::{
    builder::{Config, INPUT_TOML, OUTPUT_BUILD_DIR},
    log::build::{info, warning},
};
use std::env::consts::EXE_SUFFIX;
use std::fs::write;
use xasm::compile::Compile;
use xassembler::{Golang, Rust};

pub fn build(execute: bool) -> Result<(), String> {
    info("Reading", "toml");

    let config = Config::from_file(&format!("{}.toml", INPUT_TOML))?;

    info("Starting", "build");
    let build_output = config.build(None, OUTPUT_BUILD_DIR)?;

    let output_script = build_output.0;
    let output_path = format!("{}/{}.x", OUTPUT_BUILD_DIR, "main");
    let foreign_package_paths = (build_output.1)
        .iter()
        .map(|s| format!("{}/{}", OUTPUT_BUILD_DIR, s))
        .collect::<Vec<String>>();

    if let Err(_) = write(&output_path, &output_script) {
        return Err(format!("Could not write to file \"{}\"", output_path));
    }

    if execute {
        info("Running", "intermediate code");
        run(output_script, foreign_package_paths)?;
    } else {
        info("Compiling", "intermediate code");
        compile(output_script, foreign_package_paths)?;
    }

    Ok(())
}

fn run(output_script: String, foreign_package_paths: Vec<String>) -> Result<(), String> {
    if let Err(e) = run_xasm::<Golang>(&output_script, &foreign_package_paths) {
        if let Err(_) = run_xasm::<Rust>(&output_script, &foreign_package_paths) {
            return Err(e);
        } else {
            warning("Go build failed, but Rust build succeeded")
        }
    }

    Ok(())
}

fn compile(output_script: String, foreign_package_paths: Vec<String>) -> Result<(), String> {
    if let Err(e) = compile_xasm::<Golang>(&output_script, &foreign_package_paths) {
        if let Err(_) = compile_xasm::<Rust>(&output_script, &foreign_package_paths) {
            return Err(e);
        } else {
            warning("Go build failed, but Rust build succeeded")
        }
    }

    Ok(())
}

fn run_xasm<T: Compile>(
    output_script: &str,
    foreign_package_paths: &Vec<String>,
) -> Result<(), String> {
    let compiled = T::assemble(&output_script)?;

    if let Err(e) = T::run_subcommand(
        &compiled,
        foreign_package_paths.iter().map(|s| &s[..]).collect(),
    ) {
        return Err(e);
    }

    Ok(())
}

fn compile_xasm<T: Compile>(
    output_script: &str,
    foreign_package_paths: &Vec<String>,
) -> Result<(), String> {
    let compiled = T::assemble(&output_script)?;

    if let Err(e) = T::compile_subcommand(
        &compiled,
        foreign_package_paths.iter().map(|s| &s[..]).collect(),
        &format!("{}/{}{}", OUTPUT_BUILD_DIR, "bin", EXE_SUFFIX),
    ) {
        return Err(e);
    }

    Ok(())
}