use std::fs;

use compiler::compile;
use parser::parse;
use semantics::{check, Semantics};
use vm::{eval, Context};

pub mod compiler;
pub mod parser;
pub mod semantics;
pub mod tokens;
pub mod vm;

pub fn process_file(file: &str) {
    let source = match fs::read_to_string(file) {
        Ok(c) => c,
        Err(e) => {
            eprintln!("Unable to read file {file}: {e}");
            return;
        }
    };

    // What am I doing here?
    let (tree, lines) = parse(&source);
    let semantics = Semantics::new(&tree, &lines);
    check(&semantics);

    // OK now there might be errors.
    let mut errors = semantics.snapshot_errors();
    if errors.len() > 0 {
        errors.reverse();
        for e in errors {
            eprintln!("{file}: {}:{}: {}", e.start.0, e.start.1, e.message);
        }
        return;
    }

    let module = compile(&semantics);
    let main_function = module.functions[module.init].clone();

    let mut context = Context::new(module.clone());
    match eval(&mut context, main_function, vec![]) {
        Ok(v) => {
            println!("{:?}", v);
        }
        Err(e) => {
            eprintln!("{:?}", e);
        }
    }
}
