wcore 0.5.1

A highly abstracted mathematical programming language
Documentation
use crate::models::{Token, Token::*, WFunc, WTokens};
use crate::utils::{as_wcode, Utils};
use itertools::Itertools;
use phf::phf_map;

fn sum(data: WTokens) -> WTokens {
    let nums = data.as_nums();
    as_wcode(vec![nums.iter().sum()])
}

fn add(mut data: WTokens) -> WTokens {
    let x = data.get_par(2);
    data.push(Value(
        x.iter()
            .map(|value| match value {
                Value(content) => content,
                _ => panic!("Incorrect type found. Found {:?} but expected Value", data),
            })
            .sum(),
    ));
    data
}

fn sub(mut data: WTokens) -> WTokens {
    let x = data.get_par(2);
    let y = x
        .iter()
        .map(|value| match value {
            Value(content) => content,
            _ => panic!("Incorrect type found. Found {:?} but expected Value", data),
        })
        .collect::<Vec<_>>();
    let result = y[1] - y[0];
    data.push(Value(result));
    data
}

fn mul(mut data: WTokens) -> WTokens {
    let x = data.get_par(2);
    let y = x
        .iter()
        .map(|value| match value {
            Value(content) => content,
            _ => panic!("Incorrect type found. Found {:?} but expected Value", data),
        })
        .collect::<Vec<_>>();
    let result = y[1] * y[0];
    data.push(Value(result));
    data
}

fn div(mut data: WTokens) -> WTokens {
    let x = data.get_par(2);
    let y = x
        .iter()
        .map(|value| match value {
            Value(content) => content,
            _ => panic!("Incorrect type found. Found {:?} but expected Value", data),
        })
        .collect::<Vec<_>>();
    let result = y[1] / y[0];
    data.push(Value(result));
    data
}

fn modulo(mut data: WTokens) -> WTokens {
    let x = data.get_par(2);
    let y = x
        .iter()
        .map(|value| match value {
            Value(content) => content,
            _ => panic!("Incorrect type found. Found {:?} but expected Value", data),
        })
        .collect::<Vec<_>>();
    let result = y[1] % y[0];
    data.push(Value(result));
    data
}

fn len(data: WTokens) -> WTokens {
    let length = data.len() as f64;
    vec![Value(length)]
}

fn reverse(data: WTokens) -> WTokens {
    data.iter().rev().cloned().collect::<Vec<_>>()
}

fn output(data: WTokens) -> WTokens {
    println!("{}", data.literal());
    data
}

fn eq(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let result = match parameters {
        (Value(x), Value(y)) => x == y,
        (Function(x), Function(y)) | (FunctionLiteral(x), FunctionLiteral(y)) => x == y,
        (Container(x), Container(y))
        | (Atom(x), Atom(y))
        | (ContainerLiteral(x), ContainerLiteral(y)) => x == y,
        (Parameter(x), Parameter(y)) => x == y,
        _ => panic!("Incorrect tokens"),
    };

    let token = Value(match result {
        true => 1.0,
        false => 0.0,
    });

    data.push(token);
    data
}

fn or(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let token = Value(match parameters {
        (Value(x), Value(y)) => match (x != 0.0) || (y != 0.0) {
            true => 1.0,
            _ => 0.0,
        },
        _ => 0.0,
    });

    data.push(token);
    data
}

fn not(mut data: WTokens) -> WTokens {
    let par = &data.get_par(1)[0];

    let token = Value(match par {
        Value(x) => {
            if *x == 0.0 {
                1.0
            } else {
                0.0
            }
        }
        _ => panic!("Incorrect type found. Found {:?} but expected Value", par),
    });

    data.push(token);
    data
}

fn and(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let token = Value(match parameters {
        (Value(x), Value(y)) => match (x != 0.0) && (y != 0.0) {
            true => 1.0,
            _ => 0.0,
        },
        _ => 0.0,
    });

    data.push(token);
    data
}

fn greater(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let token = Value(match parameters {
        (Value(x), Value(y)) => match y > x {
            true => 1.0,
            _ => 0.0,
        },
        _ => 0.0,
    });

    data.push(token);
    data
}

fn less(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let token = Value(match parameters {
        (Value(x), Value(y)) => match y < x {
            true => 1.0,
            _ => 0.0,
        },
        _ => 0.0,
    });

    data.push(token);
    data
}

fn if_else(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(3);
    let parameters: (Token, Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    let selected = match parameters.0 {
        Value(x) => {
            if x != 0.0 {
                parameters.1
            } else {
                parameters.2
            }
        }

        _ => parameters.2,
    };

    let mut convered = match selected {
        Group(x) => x,
        ContainerLiteral(x) => vec![Container(x)],
        FunctionLiteral(x) => vec![Function(x)],
        _ => vec![selected],
    };

    data.append(&mut convered);
    data
}

fn expand(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(2);
    let parameters: (Token, Token) = par_arr.iter().cloned().collect_tuple().unwrap();

    match parameters {
        (Value(n), Group(group)) => {
            for _ in 0..n as usize {
                data.append(&mut group.clone())
            }
        }
        _ => panic!(
            "Incorrect type found. Found {:?} but expected (Value, Group)",
            data
        ),
    }

    data
}

fn release(mut data: WTokens) -> WTokens {
    let par_arr = data.get_par(1);
    let parameters = &par_arr[0];

    match parameters {
        Group(group) => data.append(&mut group.clone()),
        _ => panic!("Incorrect type found. Found {:?} but expected Group", data),
    };

    data
}

fn axe(data: WTokens) -> WTokens {
    data[..data.len() - 1].to_vec()
}

fn bundle(data: WTokens) -> WTokens {
    vec![Group(data)]
}

pub static FUNCTIONS: phf::Map<&'static str, WFunc> = phf_map! {
    "sum" => sum,
    "add" => add,
    "sub" => sub,
    "mul" => mul,
    "div" => div,
    "mod" => modulo,
    "+" => add,
    "-" => sub,
    "*" => mul,
    "/" => div,
    "%" => modulo,
    ">" => greater,
    "<" => less,
    "||" => or,
    "or" => or,
    "&&" => and,
    "and" => and,
    "not" => not,
    "len" => len,
    "reverse" => reverse,
    "OUTPUT" => output,
    "eq" => eq,
    "if" => if_else,
    "expand" => expand,
    "release" => release,
    "axe" => axe,
    "bundle" => bundle
};