nyavascript 0.1.0

Lisp implementation. Called NyavaScript because I'm a monster
Documentation
mod error;
pub use error::*;

mod syntax;
pub use syntax::Syntax;

#[cfg(test)]
mod test;

use std::vec::IntoIter;
use super::lexical_analysis::Token;

pub fn parse(tokens: Vec<Token>) -> Result<Syntax, SyntaxError> {
    let mut tokens = tokens.into_iter();

    let ret = match tokens.next() {
        Some(tok) => match tok {
            Token::OpenList => {
                let (syn, it) = parse_list(tokens)?;

                if it.count() > 0 {
                    Err(SyntaxError::UnexpectedTrailingTokensError)
                } else {
                    Ok(syn)
                }
            }
            _ => Err(SyntaxError::NoRootListError),
        },
        None => Err(SyntaxError::NoSymbolsError),
    };

    ret
}

pub fn parse_quote(mut tokens: IntoIter<Token>) -> Result<(Syntax, IntoIter<Token>), SyntaxError> {
    let quoted = match tokens.next() {
        Some(tok) => match tok {
            Token::Dot => todo!(),
            Token::Symbol(s) => Syntax::Symbol(s),
            Token::String(s) => Syntax::String(s),
            Token::Number(n) => Syntax::Number(n),
            Token::OpenList => {
                let (syn, it) = parse_list(tokens)?;

                tokens = it;
                syn
            }
            Token::CloseList => return Err(SyntaxError::QuoteMissingItemError),
            Token::Quote => {
                let (syn, it) = parse_quote(tokens)?;

                tokens = it;
                syn
            }
        },
        None => return Err(SyntaxError::QuoteMissingItemError),
    };

    Ok((
        Syntax::List(vec![
            Syntax::symbol("quote"),
            quoted,
        ]),
        tokens
    ))
}

pub fn parse_list(mut tokens: IntoIter<Token>) -> Result<(Syntax, IntoIter<Token>), SyntaxError> {
    let mut ret = Vec::new();

    while let Some(tok) = tokens.next() {
        match tok {
            Token::Dot => return parse_list_remainder_as_dot(ret, tokens),
            Token::Symbol(s) => ret.push(Syntax::Symbol(s)),
            Token::String(s) => ret.push(Syntax::String(s)),
            Token::Number(n) => ret.push(Syntax::Number(n)),
            Token::Quote => ret.push({
                let (syn, it) = parse_quote(tokens)?;

                tokens = it;
                syn
            }),
            Token::OpenList => ret.push({
                let (syn, it) = parse_list(tokens)?;

                tokens = it;
                syn
            }),
            Token::CloseList =>  {
                let mut x = false;
                if ret.len() == 1 {
                    if let Some(Syntax::List(l)) = ret.first() {
                        if let Some(Syntax::Symbol(s)) = l.first() {
                            if s == "quote" {
                                x = true;
                            }
                        }
                    }
                }

                if x {
                    ret = match ret.remove(0) {
                        Syntax::List(l) => l,
                        _ => panic!("This should never happen"),
                    }
                }
                return Ok((Syntax::List(ret), tokens))
            }
        }
    }


    Err(SyntaxError::UnmatchedOpenListError)
}

pub fn parse_list_remainder_as_dot(
    mut list: Vec<Syntax>,
    mut tokens: IntoIter<Token>
) -> Result<(Syntax, IntoIter<Token>), SyntaxError> {
    let car = match list.pop() {
        Some(x) => Some(x),
        None => None,
    };

    match tokens.next() {
        Some(x) => match x {
            Token::Dot => return Err(SyntaxError::BadInfixDotNotation),
            Token::OpenList => {
                let (syn, it) = parse_list(tokens)?;

                tokens = it;

                let ret = Syntax::dot(
                    car,
                    Some(syn),
                );

                list.push(ret);
                let ret = Syntax::List(list);

                match tokens.next() {
                    Some(Token::CloseList) => return Ok((ret, tokens)),
                    None => return Err(SyntaxError::UnmatchedOpenListError),
                    _ => return Err(SyntaxError::BadInfixDotNotation),
                }
            },
            Token::Quote => {
                let (syn, it) = parse_quote(tokens)?;

                tokens = it;

                let ret = Syntax::dot(
                    car,
                    Some(syn),
                );

                list.push(ret);
                let ret = Syntax::List(list);

                match tokens.next() {
                    Some(Token::CloseList) => return Ok((ret, tokens)),
                    None => return Err(SyntaxError::UnmatchedOpenListError),
                    _ => return Err(SyntaxError::BadInfixDotNotation),
                }
            },
            Token::CloseList =>  {
                let ret = Syntax::dot(
                    car,
                    None,
                );

                list.push(ret);
                let ret = Syntax::List(list);

                return Ok((ret, tokens))
            }
            Token::Symbol(_)
            | Token::String(_)
            | Token::Number(_) => {
                let syn = match x {
                    Token::Symbol(s) => Syntax::Symbol(s),
                    Token::String(s) => Syntax::String(s),
                    Token::Number(n) => Syntax::Number(n),
                    _ => panic!("This should never happen"),
                };

                let ret = Syntax::dot(
                    car,
                    Some(syn),
                );

                list.push(ret);
                let ret = Syntax::List(list);

                match tokens.next() {
                    Some(Token::CloseList) => return Ok((ret, tokens)),
                    None => return Err(SyntaxError::UnmatchedOpenListError),
                    _ => return Err(SyntaxError::BadInfixDotNotation),
                }
            },
        },
        None => return Err(SyntaxError::UnmatchedOpenListError)
    };
}