rsh-crate 0.2.2

A simple shell written in rust, build for educational purpose. My goal is to learn more about rust and how interpreters work under the hood.
use crate::{Values, VarTypes};
use std::collections::{HashMap, VecDeque};

type Operations = fn(VarTypes, VarTypes) -> VarTypes;
type Comparision = fn(VarTypes, VarTypes) -> bool;

enum StateCompare {
    Normal,
    ExclamationMark,
    Equal,
    Greater,
    Less,
}

fn find_var(s: &str, values: &mut Values) -> VarTypes {
    let vars = &values.vars;
    if vars.contains_key(s) {
        values.arg_extend = false;
        return vars.get(s).unwrap().clone();
    }
    match s.parse::<i32>() {
        Ok(x) => {
            return VarTypes::I(x)
        },
        Err(_) => (),
    }
    VarTypes::N
}

fn add(var1: VarTypes, var2: VarTypes) -> VarTypes {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type == 'N' && var2_type == 'N' {
        return VarTypes::N;
    }
    if var1_type == 'N' {
        return var2;
    }
    if var2_type == 'N' {
        return var1;
    }
    if var1_type == 'I' && var2_type == 'I' {
        return VarTypes::I(var1.get_i() + var2.get_i());
    }
    VarTypes::S(var1.get_s() + &var2.get_s())
}

fn sub(var1: VarTypes, var2: VarTypes) -> VarTypes {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type == 'I' && var2_type == 'I' {
        return VarTypes::I(var1.get_i() - var2.get_i());
    }
    VarTypes::N
}

fn divi(var1: VarTypes, var2: VarTypes) -> VarTypes {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type == 'I' && var2_type == 'I' {
        return VarTypes::I(var1.get_i() / var2.get_i());
    }
    VarTypes::N
}

fn mult(var1: VarTypes, var2: VarTypes) -> VarTypes {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type == 'I' && var2_type == 'I' {
        return VarTypes::I(var1.get_i() * var2.get_i());
    }
    VarTypes::N
}

fn pow(var1: VarTypes, var2: VarTypes) -> VarTypes {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type == 'I' && var2_type == 'I' {
        if var2.get_i() < 0 {
            return VarTypes::I(1 / var1.get_i().pow((-var2.get_i()) as u32));
        }
        return VarTypes::I(var1.get_i().pow(var2.get_i() as u32));
    }
    VarTypes::N
}

fn equal(var1: VarTypes, var2: VarTypes) -> bool {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    if var1_type != var2_type {
        return false;
    }
    match var1_type {
        'I' => var1.get_i() == var2.get_i(),
        'S' => var1.get_s() == var2.get_s(),
        _ => true,
    }
}

fn isint(var1: &VarTypes, var2: &VarTypes) -> bool {
    let var1_type = var1.get_type();
    let var2_type = var2.get_type();
    var1_type == 'I' || var2_type == 'I'
}

fn inequal(var1: VarTypes, var2: VarTypes) -> bool {
    !equal(var1, var2)
}

fn greater(var1: VarTypes, var2: VarTypes) -> bool {
    if !isint(&var1, &var2) {
        return false;
    }
    return var1.get_i() > var2.get_i();
}

fn greaterequal(var1: VarTypes, var2: VarTypes) -> bool {
    if !isint(&var1, &var2) {
        return false;
    }
    if equal(var1.clone(), var2.clone()) {
        return true;
    }
    var1.get_i() > var2.get_i()
}

fn less(var1: VarTypes, var2: VarTypes) -> bool {
    if !isint(&var1, &var2) {
        return false;
    }
    return var1.get_i() < var2.get_i();
}

fn lessequal(var1: VarTypes, var2: VarTypes) -> bool {
    if !isint(&var1, &var2) {
        return false;
    }
    if equal(var1.clone(), var2.clone()) {
        return true;
    }
    var1.get_i() < var2.get_i()
}

pub fn evaluate(s: &str, values: &mut Values) -> String {
    let mut vals: VecDeque<String> = VecDeque::from([String::new()]);
    let mut curr = 0;
    let mut operations: HashMap<char, Operations> = HashMap::new();
    operations.insert('+', add);
    operations.insert('-', sub);
    operations.insert('/', divi);
    operations.insert('*', mult);
    operations.insert('^', pow);
    for c in s.chars() {
        if operations.contains_key(&c) {
            vals.push_back(c.to_string());
            vals.push_back(String::new());
            curr += 2;
            continue;
        }
        vals[curr].push(c);
    }
    if vals.len() == 0 {
        return String::new();
    }
    if vals.len() == 1 {
        return match find_var(s.trim(), values) {
            VarTypes::I(x) => x.to_string(),
            VarTypes::S(x) => x,
            VarTypes::N => String::new(),
        };
    }
    let temp = String::from(vals.pop_front().unwrap().trim());
    let mut result = match find_var(&temp, values) {
        VarTypes::N => VarTypes::S(temp),
        x => x,
    };
    while vals.len() > 0 {
        let operant = vals.pop_front().unwrap().chars().next().unwrap();
        let temp = String::from(vals.pop_front().unwrap().trim());
        let var = match find_var(&temp, values) {
            VarTypes::N => VarTypes::S(temp),
            x => x,
        };
        result = operations.get(&operant).unwrap()(result.clone(), var);
    }
    return match result {
        VarTypes::I(x) => x.to_string(),
        VarTypes::S(x) => x,
        VarTypes::N => String::new(),
    };
}

pub fn compare(s: &str, values: &mut Values) -> char {
    use StateCompare::*;
    let mut vals: Vec<VarTypes> = Vec::new();
    let mut val = String::new();
    let mut state = Normal;
    let mut comparision: Comparision = equal;
    for c in s.chars() {
        match state {
            Normal => {
                match c {
                    '!' => state = ExclamationMark,
                    '=' => state = Equal,
                    '>' => state = Greater,
                    '<' => state = Less,
                    _ => {
                        val.push(c);
                        continue;
                    }
                }
                vals.push(find_var(&val, values));
                val = String::new();
                continue;
            }
            ExclamationMark => {
                match c {
                    '=' => comparision = inequal,
                    _ => {
                        val.push('!');
                        val.push(c);
                    }
                }
                state = Normal;
            }
            Equal => {
                match c {
                    '=' => comparision = equal,
                    _ => {
                        val.push('=');
                        val.push(c);
                    }
                }
                state = Normal
            }
            Less => {
                match c {
                    '=' => comparision = lessequal,
                    _ => {
                        comparision = less;
                        val.push(c)
                    }
                }
                state = Normal;
            }
            Greater => {
                match c {
                    '=' => comparision = greaterequal,
                    _ => {
                        comparision = greater;
                        val.push(c)
                    }
                }
                state = Normal
            }
        }
    }
    vals.push(find_var(&val, values));
    if vals.len() == 0 {
        return '0';
    }
    if vals.len() == 1 {
        if vals[0].get_type() == 'I' {
            if vals[0].get_i() == 0 {
                return '0';
            }
        }
        return '1';
    }
    if comparision(vals[0].clone(), vals[1].clone()) {
        return '1';
    }
    return '0';
}