finn-assembler 0.2.2

The Finn IR Assembler
use std::cmp::{min, max};
use crate::error::*;
use crate::stdout::*;
use crate::tokenizer::*;
use crate::tokenizer::Token::*;


const SNIPPET_SIZE: usize = 10;

fn print_snippet(tokens: &Vec<Token>, i: usize) {
    let i = max(SNIPPET_SIZE/2, i);
    sub_error_info(
        &format!("{}", tokens_to_string(tokens.clone()[max(i-SNIPPET_SIZE/2, 0)..min(i+SNIPPET_SIZE/2, tokens.len())].to_vec()))
    );
}

fn find_unmatched_functions(tokens: &Vec<Token>) {
    sub_info(&format!("Checking for unmatched function delimiters..."));

    let mut index_stack = vec![];
    let mut count = 0;

    for (i, token) in tokens.iter().enumerate() {
        let change = match token {
            FunctionBegin => {
                index_stack.push(i);
                1
            },
            FunctionEnd => {
                index_stack.pop();
                -1
            },
            _ => {0}
        };

        count += change;
        if count < 0 {
            sub_error(
                &format!("Unmatched '}}' at instruction #{}", i)
            );
            print_snippet(tokens, i);
            throw();
            return;
        }
    }

    if count > 0 {
        let i = index_stack[index_stack.len()-1];
        sub_error(
            &format!("Unmatched '{{' at instruction #{}", i)
            // &format!("Unmatched '{{' at token #{}", index_stack[index_stack.len()-1])
        );
        print_snippet(tokens, i);
        throw();
    }
}


fn find_unmatched_lists(tokens: &Vec<Token>) {
    sub_info(&format!("Checking for unmatched list delimiters..."));

    let mut index_stack = vec![];
    let mut count = 0;

    for (i, token) in tokens.iter().enumerate() {
        let change = match token {
            ListBegin => {
                index_stack.push(i);
                1
            },
            ListEnd => {
                index_stack.pop();
                -1
            },
            _ => {0}
        };

        count += change;
        if count < 0 {
            sub_error(
                &format!("Unmatched ']' at instruction #{}", i)
            );
            print_snippet(tokens, i);
            throw();
            return;
        }
    }

    
    if count > 0 {
        let i = index_stack[index_stack.len()-1];
        sub_error(
            &format!("Unmatched '[' at instruction #{}", i)
        );
        print_snippet(tokens, i);
        throw();
    }
}


fn find_unexpected(tokens: &Vec<Token>) {
    sub_info(&format!("Checking for invalid tokens..."));

    for (i, token) in tokens.iter().enumerate() {
        match token {
            UnExpected(s) => {
                sub_error(
                    &format!("Unexpected '{}' at instruction #{}", s, i)
                );
                print_snippet(tokens, i);
                throw();
            },
            _ => {}
        };
    }
}



pub fn error_check(tokens: Vec<Token>) -> Vec<Token> {
    info(&format!("Performing compile time error checks"));

    find_unexpected(&tokens);
    find_unmatched_functions(&tokens);
    find_unmatched_lists(&tokens);

    if has_thrown_error() {
        error(
            &format!("Detected errors during compile time checks")
        );
        stop();
    } else {
        success("No errors detected");
    }

    return tokens;
}