luallaby 0.1.0

**Work in progress** A pure-Rust Lua interpreter/compiler
Documentation
use crate::ast::{Exp, Parser, PrefixExp};
use crate::error::{LuaError, Result};
use crate::lexer::{Pos, Spanned, Token};

use super::MAX_ASSIGN;

/// ```text
/// stat ::= varlist ‘=’ explist
/// varlist ::= var {‘,’ var}
/// explist ::= exp {‘,’ exp}
/// ```
pub struct Ass {
    pub vars: Vec<(Var, Pos)>,
    pub exps: Vec<Exp>,
}

pub enum Var {
    Name(String),
    Index(PrefixExp, Exp),
}

impl<'a> Parser<'a> {
    pub(super) fn parse_ass(&mut self, first: PrefixExp) -> Result<Ass> {
        let mut vars = vec![self.parse_var(Some(first))?];
        loop {
            match self.tok_next()?.into() {
                (pos, Token::Comma) => {
                    if vars.len() > MAX_ASSIGN {
                        // XXX: Does not need to be enforced, but Lua test suite does
                        return err!(self.source, pos, LuaError::SyntaxLimit("assignments", None));
                    }
                    vars.push(self.parse_var(None)?)
                }
                (_, Token::Is) => break,
                (pos, tok) => return err!(&*self.source, pos, LuaError::UnexpectedToken(tok)),
            }
        }

        let mut exps = vec![self.parse_exp()?];
        while let Some(Token::Comma) = self.tok_peek_opt()?.map(Spanned::inner) {
            self.tok_next()?;
            exps.push(self.parse_exp()?);
        }

        Ok(Ass { vars, exps })
    }

    fn parse_var(&mut self, parsed: Option<PrefixExp>) -> Result<(Var, Pos)> {
        let prefix_exp = match parsed {
            Some(exp) => exp,
            None => self.parse_prefix_exp()?,
        };

        Ok(match prefix_exp {
            PrefixExp::Var(name, pos) => (Var::Name(name), pos),
            PrefixExp::Index(sub, exp, pos) => (Var::Index(*sub, *exp), pos),
            _ => panic!(),
        })
    }
}