lispi 0.3.3

Lisp I interpreter
Documentation
use std::io;
use std::io::Write;
use std::process::exit;

use clap::{App, Arg};
use lispi::file_parser::get_bound_symbols;
use lispi::repl::MyHelper;
use lispi::{
    file_parser::eval_file,
    interpreter::eval,
    parser::parse,
    types::{NullableList, NIL},
};
use rustyline::history::MemHistory;
use rustyline::Config;
use rustyline::{error::ReadlineError, Editor};

fn main() {
    env_logger::builder()
        .filter_level(log::LevelFilter::Info)
        .format(|buf, record| {
            writeln!(
                buf,
                "{}: {}",
                buf.default_styled_level(record.level()),
                record.args(),
            )
        })
        .init();

    let args = App::new("lispi")
        .version("0.3.3")
        .arg(Arg::with_name("FILE").help("File to evaluate"))
        .arg(
            Arg::with_name("load_file")
                .conflicts_with("FILE")
                .short("l")
                .long("load")
                .takes_value(true)
                .value_name("FILE")
                .help("Loads the content of FILE into the REPL"),
        )
        .get_matches();

    let mut a: NullableList = NIL.into();
    if let Some(filename) = args.value_of("FILE") {
        if eval_file(filename, &mut io::stdout()).is_some() {
            exit(0);
        } else {
            exit(1);
        }
    } else if let Some(load_file) = args.value_of("load_file") {
        if let Some(a_list) = eval_file(load_file, &mut Vec::new()) {
            a = a_list;
        }
        if let Some(symbols) = get_bound_symbols(&a) {
            print!("Loaded symbols: ");
            for symbol in symbols {
                print!("{} ", symbol);
            }
            println!();
        }
    }

    let mut rl = Editor::with_history(Config::default(), MemHistory::default()).unwrap();
    rl.set_helper(Some(MyHelper::new()));

    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str()).unwrap();
                match parse(&line) {
                    Some(prog) => match eval(prog, &a) {
                        Some((result, new_a_list)) => {
                            a = new_a_list.into_owned();
                            println!("{}", result)
                        }
                        None => {
                            continue;
                        }
                    },
                    None => continue,
                }
            }
            Err(ReadlineError::Interrupted) => {
                break;
            }
            Err(ReadlineError::Eof) => {
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}