use crate::parse::Span;
use crate::err::SJFLError;
use super::{Parse, Session};

#[derive(Clone, Debug)]
pub struct Variable {
    pub index: u32,
    pub span: Span
}

impl Parse for Variable {

    fn parse(s: &[u8], mut ind: usize, session: &mut Session) -> Result<(Self, usize), SJFLError> {
        let mut buffer = vec![];

        while ind < s.len() && (48 <= s[ind] && s[ind] <= 57)  // 0 ~ 9
        || (65 <= s[ind] && s[ind] <= 90)  // A ~ Z
        || (97 <= s[ind] && s[ind] <= 122)  // a ~ z
        || s[ind] == 95  // _
        {
            buffer.push(s[ind]);
            ind += 1;
        }

        let string_index = session.intern_string(&buffer);

        if session.is_keyword(string_index) {
            return Err(SJFLError::InvalidVarName(
                String::from_utf8_lossy(&session.get_string_from_index(string_index).unwrap()).to_string(),
                Span::from_index(ind)
            ));
        }

        Ok((Variable { index: string_index, span: Span::from_index(ind) }, ind))
    }

}

impl PartialEq for Variable {

    fn eq(&self, other: &Variable) -> bool {
        self.index == other.index
    }

}

impl Eq for Variable {}

impl std::hash::Hash for Variable {
    fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {
        self.index.hash(hasher);
    }
}