whiledb 0.1.4

rust implementation of WhileDB language
Documentation
use maplit;
use num::ToPrimitive;
use crate::{interpreter::*, method};


pub fn buildin_string(state: Any) -> Result<Any> {
    let attrs = method!{
        __init__(state, _self, arg) {
            match utils::get_father_attr(arg.clone(), "__string__") {
                Some(f) => utils::call(f, VecDeque::from([arg]), state),
                None => bail!("cannot convert arg to string"),
            }
        }
        __add__(state, s, other) {
            match (any2string(s), any2string(other)) {
                (Some(s1), Some(s2)) => Ok(build_string(&(s1 + &s2), state)),
                _ => bail!("cannot add string with other")
            }
        }
        __getitem__(state, _self, idx) {
            let s: VecDeque<char> = match any2string(_self.clone()) {
                Some(s) => s.chars().collect(),
                None => unreachable!(),
            };
            match &*idx.clone().borrow() {
                WdAny::Obj(o) => match &o.buildin {
                    BuildIn::Tuple(t) => {
                        match t.len() {
                            1 => {
                                let idx = match obj_int::wdany2bigint(&*t[0].borrow()) {
                                    Some(idx) => match idx.to_usize() {
                                        Some(idx) => idx,
                                        None => bail!("index overflow usize"),
                                    },
                                    None => bail!("index for string must be int"),
                                };
                                match s.get(idx) {
                                    Some(res) => Ok(build_string(&res.to_string(), state)),
                                    None => bail!("string index out of range"),
                                }
                            }
                            2 => {
                                let (idxs, idxe) = match (obj_int::wdany2bigint(&*t[0].borrow()), obj_int::wdany2bigint(&*t[1].borrow())) {
                                    (Some(idxs), Some(idxe)) => match (idxs.to_usize(), idxe.to_usize()) {
                                        (Some(idxs), Some(idxe)) => (idxs, idxe),
                                        _ => bail!("index overflow usize"),
                                    },
                                    _ => bail!("slice for string must be int"),
                                };
                                if idxs > idxe || idxe > s.len() {
                                    bail!("string index out of range")
                                }
                                let res: String = s.range(idxs..idxe).collect();
                                Ok(build_string(&res, state.clone()))
                            }
                            _ => bail!("invalid string index")
                        }
                    },
                    _ => bail!("index for getitem of string can only be int")
                },
                _ => bail!("index for getitem of string can only be int")
            }
        }
        len(state, s) {
            match any2string(s) {
                Some(s) => Ok(obj_int::bigint2intinstance(BigInt::from(s.chars().count()), state)),
                None => unreachable!(),
            }
        }
        __bool__(state, arg) {
            match any2string(arg) {
                Some(s) => match s.len() {
                    0 => utils::get_buildin_var("false", state),
                    _ => utils::get_buildin_var("true", state)
                },
                None => unreachable!(),
            }
        }
        __int__(state, arg) {
            match any2string(arg) {
                Some(s) => Ok(obj_int::bigint2intinstance(s.parse::<BigInt>()?, state)),
                None => unreachable!(),
            }
        }
        __float__(state, arg) {
            match any2string(arg) {
                Some(s) => Ok(obj_float::float2any(s.parse::<f64>()?, state)),
                None => unreachable!(),
            }
        }
        __string__(_state, arg) {
            Ok(arg)
        }
    };
    let res = Rc::new(RefCell::new(WdAny::Obj(Object{
        buildin: BuildIn::Not,
        attrs: attrs
    })));
    utils::set_attr(
        state, 
        "string", 
        res.clone()
    )?;
    Ok(res)
}

pub fn buildin_string_post(type_obj: Any, state: Any) -> Result<()> {
    let attrs = maplit::hashmap! {
        "__type__".to_string() => utils::get_buildin_var("type", state.clone())?,
        "__name__".to_string() => obj_string::build_string("string", state.clone())
    };
    for (k, v) in attrs.into_iter() {
        utils::set_attr(type_obj.clone(), &k, v)?;
    }
    Ok(())
}


pub fn build_string_raw(raw: &str, state: Any) -> Result<Any> {
    Ok(Rc::new(RefCell::new(WdAny::Obj(Object {
        buildin: BuildIn::String(syn::parse_str::<syn::LitStr>(raw)?.value()),
        attrs: maplit::hashmap! {
            "__type__".to_string() => utils::get_buildin_var("string", state.clone()).unwrap()
        }
    }))))
}

pub fn build_string(s: &str, state: Any) -> Any {
    Rc::new(RefCell::new(WdAny::Obj(Object {
        buildin: BuildIn::String(s.to_string()),
        attrs: maplit::hashmap! {
            "__type__".to_string() => utils::get_buildin_var("string", state.clone()).unwrap()
        }
    })))
}

pub fn any2string(x: Any) -> Option<String> {
    match &*x.clone().borrow() {
        WdAny::Obj(o) => match &o.buildin {
            BuildIn::String(s) => Some(s.clone()),
            _ => None
        },
        _ => None,
    }
}