use crate::err::{SJFLError, Span};
use crate::value::Value;
use super::{Variable, List, InternedString, Table, match_exact, Parse, Session};
use hmath::Ratio;

impl Parse for Value {

    // if the first character is ` `, it dies!
    fn parse(s: &[u8], ind: usize, session: &mut Session) -> Result<(Self, usize), SJFLError> {

        match s[ind] {
            34 | 39 => {  // " | '
                let (s, ind) = InternedString::parse(s, ind, session)?;

                Ok((Value::String(s), ind))
            }
            45 | 48..=57 => {  // - | 0-9
                let (n, ind) = Ratio::parse(s, ind, session)?;

                Ok((Value::Number(n), ind))
            }
            65..=90 | 95 => {  // A-Z | _

                if let Ok(n) = match_exact(s, ind, b"True") {
                    Ok((Value::Boolean(true), n))
                }

                else if let Ok(n) = match_exact(s, ind, b"False") {
                    Ok((Value::Boolean(false), n))
                }

                else if let Ok(n) = match_exact(s, ind, b"None") {
                    Ok((Value::None, n))
                }

                else {
                    let (var, ind) = Variable::parse(s, ind, session)?;

                    Ok((Value::Variable(var), ind))
                }

            }
            91 => {  // [
                let (l, ind) = List::parse(s, ind, session)?;

                Ok((Value::List(l), ind))
            }
            97..=122 => {  // a-z

                if let Ok(n) = match_exact(s, ind, b"true") {
                    Ok((Value::Boolean(true), n))
                }

                else if let Ok(n) = match_exact(s, ind, b"false") {
                    Ok((Value::Boolean(false), n))
                }

                else if let Ok(n) = match_exact(s, ind, b"null") {
                    Ok((Value::None, n))
                }

                else {
                    let (var, ind) = Variable::parse(s, ind, session)?;

                    Ok((Value::Variable(var), ind))
                }


            }
            123 => {  // {
                let (t, ind) = Table::parse(s, ind, session)?;

                Ok((Value::Table(t), ind))
            }
            _ => Err(SJFLError::UnexpectedChar(s[ind], Span::from_index(ind)))
        }

    }

}