brim 4.2.2

An optimizing brain* interpreter.
Documentation
use std::{
    fs::{self, File},
    io::{stdout, stdin, BufReader, Read},
};

use sarge::prelude::*;

use brim::{
    helper::{err, warn},
    interpret, parse,
    token::optimize,
};

#[cfg(feature = "debug")]
sarge! {
    Args,

    'h' help: bool,
    #ok 'i' input: String,
    #ok 'o' output: String,

    #ok 'w' @BRIM_DEBUG_WIDTH debug_width: usize,
}

#[cfg(not(feature = "debug"))]
sarge! {
    Args,

    'h' help: bool,
    #ok 'i' input: String,
    #ok 'o' output: String,
}

fn main() {
    let (args, files) = Args::parse().unwrap_or_else(|e| err("failed to parse arguments", e));

    if args.help || files.is_empty() {
        warn(include_str!("usage.txt"));

        return;
    }

    let mut stdin = if let Some(i) = args.input {
        let file = File::open(i).unwrap_or_else(|e| err("failed to open input file", e));

        Box::new(BufReader::new(file)) as Box<dyn Read>
    } else {
        Box::new(BufReader::new(stdin())) as Box<dyn Read>
    }.bytes().map(|data| data.unwrap_or_else(|e| err("failed to read input", e)));

    if let Some(o) = args.output {
        let mut file = File::create(o).unwrap_or_else(|e| err("failed to open output file", e));

        for filename in files.iter().skip(1) {
            let input = fs::read_to_string(filename).unwrap_or_else(|e| err("failed", e));

            let toks = parse(&input);
            let toks = optimize(&toks);

            #[cfg(not(feature = "debug"))]
            interpret(&toks, &mut stdin, &mut file);

            #[cfg(feature = "debug")]
            interpret(&toks, &mut stdin, &mut file, args.debug_width.unwrap_or(8));
        }
    } else {
        for filename in files.iter().skip(1) {
            let input = fs::read_to_string(filename).unwrap_or_else(|e| err("failed", e));

            let toks = parse(&input);
            let toks = optimize(&toks);

            #[cfg(not(feature = "debug"))]
            interpret(&toks, &mut stdin, &mut stdout());

            #[cfg(feature = "debug")]
            interpret(&toks, &mut stdin, &mut stdout(), args.debug_width.unwrap_or(8));
        }
    }
}