luaparse 0.2.0

A Lua 5.3 parser
Documentation
//! The Lua 5.3 parser.
//!
//! ```rust
//! # use luaparse::{InputCursor, Lexer, Parser};
//! let buf = "local a = 42;";
//! let mut parser = Parser::new(Lexer::new(InputCursor::new(buf)));
//!
//! match parser.chunk() {
//!     Ok(block) => println!("{}", block),
//!     Err(e) => eprintln!("{}", e),
//! }
//! ```

use std::borrow::Cow;
use std::fmt::{self, Display};
use std::iter::Iterator;
use std::iter::Peekable;

use crate::ast::*;
use crate::lexer::{Lexer, LexerError};
use crate::span::{HasSpan, Span};
use crate::symbol::Symbol;
use crate::token::{Token, TokenKind};

/// The error type returned by the parser.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum ParseError<'a> {
    /// An error that occured in the lexer.
    LexerError(LexerError),

    /// Expected one of X, Y, or Z, found A.
    UnexpectedToken {
        expected: Cow<'static, [TokenKind]>,
        found: TokenReference<'a>,
    },

    /// Expected variable, found a function call / a parenthesized expression.
    VarExpected {
        expr: PrefixExpr<'a>,
    },

    /// Expected a statement, found a parenthesized expression.
    StatementExpected {
        expr: ParenthesizedExpr<'a>,
    },

    /// The `break` statement is not enclosed in any loop.
    BreakOutsideLoop {
        stat: BreakStat<'a>,
    },
}

fn format_expected_list(expected: &[TokenKind]) -> String {
    match expected.len() {
        0 => "nothing".to_owned(),
        1 => expected[0].to_string(),
        2 => format!("{} or {}", expected[0], expected[1]),
        _ => {
            let mut tokens = expected
                .iter()
                .map(|kind| kind.to_string())
                .collect::<Vec<_>>();

            tokens.sort_unstable();

            format!(
                "one of {}, or {}",
                tokens[..(tokens.len() - 1)].join(", "),
                tokens[tokens.len() - 1],
            )
        },
    }
}

impl Display for ParseError<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            Self::LexerError(e) => e.to_string(),
            Self::UnexpectedToken { expected, found } => format!(
                "expected {}, found {}",
                format_expected_list(expected),
                found.token.kind()
            ),
            Self::VarExpected { expr } => format!(
                "expected a variable, found {}",
                match expr {
                    PrefixExpr::Parenthesized(_) => "a parenthesized expression",
                    PrefixExpr::Call(_) => "a function call",
                    _ => unreachable!(),
                }
            ),
            Self::StatementExpected { .. } => {
                "expected a statement, found a parenthesized expression".to_owned()
            }
            Self::BreakOutsideLoop { .. } => {
                "the break statement is not enclosed in any loop".to_owned()
            }
        };

        write!(formatter, "{}", s)
    }
}

impl std::error::Error for ParseError<'_> {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::LexerError(ref e) => Some(e),
            _ => None,
        }
    }
}

impl HasSpan for ParseError<'_> {
    fn span(&self) -> Span {
        match self {
            Self::LexerError(e) => e.span(),
            Self::UnexpectedToken { found, .. } => found.span(),
            Self::VarExpected { expr } => expr.span(),
            Self::StatementExpected { expr } => expr.span(),
            Self::BreakOutsideLoop { stat } => stat.span(),
        }
    }
}

/// Lexer which skips whitespace and comment tokens, giving TokenReference
#[derive(Clone, Debug)]
struct RefLexer<'a> {
    lexer: Peekable<Lexer<'a>>,
    saved: Option<Token<'a>>, // same as using Peekable, but easier to use in this case
    leading_trivia: Vec<Token<'a>>,
    trailing_trivia: Vec<Token<'a>>,
}

impl<'a> RefLexer<'a> {
    fn new(lexer: Lexer<'a>) -> RefLexer<'a> {
        RefLexer {
            lexer: lexer.peekable(),
            saved: None,
            leading_trivia: Vec::new(),
            trailing_trivia: Vec::new(),
        }
    }
}

impl<'a> Iterator for RefLexer<'a> {
    type Item = Result<TokenReference<'a>, LexerError>;

    fn next(&mut self) -> Option<Self::Item> {
        let token = loop {
            let saved = self.saved.take().map(Ok).into_iter();
            let next = saved.chain(&mut self.lexer).next()?;
            match next {
                Ok(t) if t.kind().is_trivia() => {
                    self.leading_trivia.push(t);
                }
                Ok(t) => break t,
                Err(e) => return Some(Err(e)),
            }
        };

        loop {
            match self.lexer.peek() {
                Some(Ok(t)) if t.kind().is_trivia() => self
                    .trailing_trivia
                    .push(self.lexer.next().unwrap().unwrap()),
                Some(Ok(_)) => {
                    self.saved = Some(self.lexer.next().unwrap().unwrap());
                    break;
                }
                _ => break,
            }
        }

        Some(Ok(TokenReference {
            leading_trivia: self.leading_trivia.drain(..).collect(),
            token,
            trailing_trivia: self.trailing_trivia.drain(..).collect(),
        }))
    }
}

/// The parser.
#[derive(Clone, Debug)]
pub struct Parser<'a> {
    lexer: Peekable<RefLexer<'a>>,
    is_inside_loop: bool,
}

trait Expect {
    fn matches(&self, token: TokenKind) -> bool;
    fn to_token_kinds(&self) -> Cow<'static, [TokenKind]>;
}

impl Expect for &'static [TokenKind] {
    fn matches(&self, token: TokenKind) -> bool {
        self.contains(&token)
    }

    fn to_token_kinds(&self) -> Cow<'static, [TokenKind]> {
        (*self).into()
    }
}

impl Expect for &'_ [Symbol] {
    fn matches(&self, token: TokenKind) -> bool {
        if let TokenKind::Symbol(symbol) = token {
            self.contains(&symbol)
        } else {
            false
        }
    }

    fn to_token_kinds(&self) -> Cow<'static, [TokenKind]> {
        self.iter().copied().map(TokenKind::Symbol).collect()
    }
}

impl<T: Clone + Into<TokenKind>> Expect for T {
    fn matches(&self, token: TokenKind) -> bool {
        self.clone().into() == token
    }

    fn to_token_kinds(&self) -> Cow<'static, [TokenKind]> {
        vec![self.clone().into()].into()
    }
}

macro_rules! lookahead {
    ($s:ident { $($expect:expr => $expr:expr,)+ _ => $catch:expr, }) => ({
        match $s.lexer.peek() {
            $(Some(Ok(t)) if $expect.matches(t.token.kind()) => $expr,)+
            _ => $catch,
        }
    });

    ($s:ident { $($expect:expr => $expr:expr,)+ }) => ({
        let expected = || {
            vec![$($expect.to_token_kinds().into_owned(), )+].into_iter().flatten().collect()
        };

        match $s.lexer.peek() {
            $(Some(Ok(t)) if $expect.matches(t.token.kind()) => $expr,)+
            Some(Ok(t)) => return Err(ParseError::UnexpectedToken {
                expected: expected(),
                found: t.clone(),
            }),
            Some(Err(e)) => return Err(ParseError::LexerError(e.clone())),
            None => panic!("lookahead called after reaching end of file"),
        }
    })
}

impl<'a> Parser<'a> {
    /// Creates a new parser from the given lexer instance.
    pub fn new(lexer: Lexer<'a>) -> Parser<'a> {
        Parser {
            lexer: RefLexer::new(lexer).peekable(),
            is_inside_loop: false,
        }
    }

    /// Parses the whole buffer as a Lua block.
    pub fn chunk(&mut self) -> Result<Block<'a>, ParseError<'a>> {
        let block = self.block()?;
        self.expect(TokenKind::Eof)?;

        Ok(block)
    }

    fn expect(&mut self, variants: impl Expect) -> Result<TokenReference<'a>, ParseError<'a>> {
        match self.lexer.next() {
            Some(Ok(t)) if variants.matches(t.token.kind()) => Ok(t),
            Some(Ok(t)) => Err(ParseError::UnexpectedToken {
                expected: variants.to_token_kinds(),
                found: t,
            }),
            Some(Err(e)) => Err(ParseError::LexerError(e)),
            None => panic!("expect called after reaching eof of file"),
        }
    }

    fn number(&mut self) -> Result<NumberLit<'a>, ParseError<'a>> {
        self.expect(TokenKind::Number).map(NumberLit)
    }

    fn nil(&mut self) -> Result<NilLit<'a>, ParseError<'a>> {
        self.expect(Symbol::Nil).map(NilLit)
    }

    fn boolean(&mut self) -> Result<BooleanLit<'a>, ParseError<'a>> {
        self.expect(BooleanLit::TOKEN_KINDS).map(BooleanLit)
    }

    fn string(&mut self) -> Result<StringLit<'a>, ParseError<'a>> {
        self.expect(TokenKind::String).map(StringLit)
    }

    fn name(&mut self) -> Result<Name<'a>, ParseError<'a>> {
        self.expect(TokenKind::Ident).map(Name)
    }

    fn table_constructor(&mut self) -> Result<TableConstructor<'a>, ParseError<'a>> {
        let opening = self.expect(Symbol::CurlyBracketLeft)?;
        let mut fields = Vec::<TableField<'a>>::new();

        let closing = loop {
            if let Some(last) = fields.last_mut() {
                if last.separator.is_none() {
                    let t = self.expect(
                        &[Symbol::Comma, Symbol::Semicolon, Symbol::CurlyBracketRight][..],
                    )?;

                    if t.token.kind() == TokenKind::Symbol(Symbol::CurlyBracketRight) {
                        break t;
                    } else {
                        last.separator = Some(t);
                    }
                }
            }

            let (key, value) = lookahead!(self {
                Symbol::CurlyBracketRight => {
                    break self.expect(Symbol::CurlyBracketRight)?
                },

                TokenKind::Ident => {
                    let key = self.name()?;
                    lookahead!(self {
                        Symbol::Assign => {
                            let eq = self.expect(Symbol::Assign)?;
                            let value = self.expr()?;
                            (Some((TableKey::Name { key }, eq)), value)
                        },
                        _ => {
                            let prefix = self.prefix_expr_right(PrefixExpr::Var(Var::Name(key)))?;
                            let expr = self.expr_rec_right(Expr::Prefix(prefix), 0)?;
                            (None, expr)
                        },
                    })
                },

                Symbol::SquareBracketLeft => {
                    let opening = self.expect(Symbol::SquareBracketLeft)?;
                    let key = Box::new(self.expr()?);
                    let closing = self.expect(Symbol::SquareBracketRight)?;
                    let eq = self.expect(Symbol::Assign)?;
                    let value = self.expr()?;
                    let key = TableKey::Expr {
                        brackets: Brackets(opening, closing), key,
                    };
                    (Some((key, eq)), value)
                },

                _ => (None, self.expr()?),
            });

            fields.push(TableField {
                key,
                value: Box::new(value),
                separator: None,
            });
        };

        Ok(TableConstructor {
            brackets: Brackets(opening, closing),
            fields,
        })
    }

    fn unop(&mut self) -> Result<UnOp<'a>, ParseError<'a>> {
        self.expect(UnOp::TOKEN_KINDS).map(UnOp)
    }

    fn binop(&mut self) -> Result<BinOp<'a>, ParseError<'a>> {
        self.expect(BinOp::TOKEN_KINDS).map(BinOp)
    }

    fn peek_binop(&mut self) -> Option<BinOpKind> {
        let t = self.lexer.peek()?.as_ref().ok()?;
        match t.token.kind() {
            TokenKind::Symbol(s) => BinOpKind::from_symbol(s),
            _ => None,
        }
    }

    fn var_field(&mut self) -> Result<VarField<'a>, ParseError<'a>> {
        lookahead!(self {
            Symbol::Period => {
                let period = self.expect(Symbol::Period)?;
                let key = self.name()?;
                Ok(VarField::Name { period, key })
            },
            Symbol::SquareBracketLeft => {
                let opening = self.expect(Symbol::SquareBracketLeft)?;
                let key = Box::new(self.expr()?);
                let closing = self.expect(Symbol::SquareBracketRight)?;
                Ok(VarField::Expr { brackets: Brackets(opening, closing), key })
            },
        })
    }

    fn punctuated<T, P>(
        &mut self,
        sep: impl Expect + Clone,
        mut f: P,
    ) -> Result<Punctuated<'a, T>, ParseError<'a>>
    where
        P: FnMut(&mut Self) -> Result<T, ParseError<'a>>,
    {
        let mut pairs = Vec::new();

        let first = f(self)?;
        pairs.push((first, None));

        loop {
            lookahead!(self {
                &sep => {
                    let separator = self.expect(sep.clone())?;
                    pairs.last_mut().unwrap().1.replace(separator);
                    pairs.push((f(self)?, None));
                },

                _ => break,
            });
        }

        Ok(Punctuated { pairs })
    }

    fn parenthesized_list<T, F>(&mut self, f: F) -> Result<ParenthesizedList<'a, T>, ParseError<'a>>
    where
        F: FnMut(&mut Self) -> Result<T, ParseError<'a>>,
    {
        let opening = self.expect(Symbol::RoundBracketLeft)?;
        let list = lookahead!(self {
            Symbol::RoundBracketRight => {
                Punctuated { pairs: Vec::new() }
            },
            _ => self.punctuated(Symbol::Comma, f)?,
        });

        let closing = self.expect(Symbol::RoundBracketRight)?;
        let brackets = Brackets(opening, closing);

        Ok(ParenthesizedList { brackets, list })
    }

    fn function_call(
        &mut self,
        prefix_expr: PrefixExpr<'a>,
    ) -> Result<FunctionCall<'a>, ParseError<'a>> {
        let callee = lookahead!(self {
            Symbol::Colon => {
                let colon = self.expect(Symbol::Colon)?;
                let name = self.name()?;

                FunctionCallee::Method {
                    object: Box::new(prefix_expr),
                    colon,
                    name,
                }
            },

            _ => FunctionCallee::Expr(Box::new(prefix_expr)),
        });

        let args = lookahead!(self {
            Symbol::CurlyBracketLeft => {
                FunctionArgs::TableConstructor(self.table_constructor()?)
            },

            TokenKind::String => {
                FunctionArgs::StringLit(self.string()?)
            },

            Symbol::RoundBracketLeft => {
                FunctionArgs::ParenthesizedList(
                    self.parenthesized_list(|s| s.expr().map(Box::new))?
                )
            },
        });

        Ok(FunctionCall { callee, args })
    }

    fn prefix_expr_right(
        &mut self,
        mut left: PrefixExpr<'a>,
    ) -> Result<PrefixExpr<'a>, ParseError<'a>> {
        const CALL_TOKENS: &[TokenKind] = &[
            TokenKind::Symbol(Symbol::CurlyBracketLeft),
            TokenKind::String,
            TokenKind::Symbol(Symbol::RoundBracketLeft),
            TokenKind::Symbol(Symbol::Colon),
        ];

        loop {
            lookahead!(self {
                &[Symbol::SquareBracketLeft, Symbol::Period][..] => {
                    let field = self.var_field()?;
                    left = PrefixExpr::Var(Var::Field(Box::new(left), field));
                },

                CALL_TOKENS => {
                    left = PrefixExpr::Call(self.function_call(left)?);
                },

                _ => break,
            });
        }

        Ok(left)
    }

    fn prefix_expr(&mut self) -> Result<PrefixExpr<'a>, ParseError<'a>> {
        let left = lookahead!(self {
            Symbol::RoundBracketLeft => {
                PrefixExpr::Parenthesized(self.parenthesized_expr()?)
            },

            TokenKind::Ident => {
                PrefixExpr::Var(Var::Name(self.name()?))
            },
        });

        self.prefix_expr_right(left)
    }

    fn parenthesized_expr(&mut self) -> Result<ParenthesizedExpr<'a>, ParseError<'a>> {
        let opening = self.expect(Symbol::RoundBracketLeft)?;
        let expr = self.expr()?;
        let closing = self.expect(Symbol::RoundBracketRight)?;
        Ok(ParenthesizedExpr {
            brackets: Brackets(opening, closing),
            expr: Box::new(expr),
        })
    }

    /// Parses a Lua expression.
    pub fn expr(&mut self) -> Result<Expr<'a>, ParseError<'a>> {
        self.expr_rec(0)
    }

    fn expr_rec(&mut self, min_bp: u8) -> Result<Expr<'a>, ParseError<'a>> {
        let left = lookahead!(self {
            Symbol::Nil => {
                Expr::Nil(self.nil()?)
            },

            BooleanLit::TOKEN_KINDS => {
                Expr::Boolean(self.boolean()?)
            },

            TokenKind::Number => {
                Expr::Number(self.number()?)
            },

            TokenKind::String => {
                Expr::String(self.string()?)
            },

            Symbol::TriplePeriod => {
                Expr::Vararg(self.vararg()?)
            },

            Symbol::CurlyBracketLeft => {
                Expr::TableConstructor(self.table_constructor()?)
            },

            &[TokenKind::Ident, TokenKind::Symbol(Symbol::RoundBracketLeft)][..] => {
                Expr::Prefix(self.prefix_expr()?)
            },

            Symbol::Function => Expr::Function(self.function_expr()?),

            UnOp::TOKEN_KINDS => {
                let op = self.unop()?;
                let ((), r_bp) = op.kind().binding_power();
                let right = self.expr_rec(r_bp)?;
                Expr::UnOp(UnOpExpr {
                    op, right: Box::new(right)
                })
            },
        });

        self.expr_rec_right(left, min_bp)
    }

    fn expr_rec_right(
        &mut self,
        mut left: Expr<'a>,
        min_bp: u8,
    ) -> Result<Expr<'a>, ParseError<'a>> {
        while let Some(op_kind) = self.peek_binop() {
            let (l_bp, r_bp) = op_kind.binding_power();
            if l_bp < min_bp {
                break;
            }

            let op = self.binop()?;
            let right = self.expr_rec(r_bp)?;
            left = Expr::BinOp(BinOpExpr {
                left: Box::new(left),
                op,
                right: Box::new(right),
            });
        }

        Ok(left)
    }

    const TERMINATORS: &'static [TokenKind] = &[
        TokenKind::Symbol(Symbol::End),
        TokenKind::Symbol(Symbol::Until),
        TokenKind::Symbol(Symbol::Else),
        TokenKind::Symbol(Symbol::ElseIf),
        TokenKind::Eof,
    ];

    /// Parses a block (a list of statements).
    ///
    /// Unless you don't need to parse the whole buffer, use `chunk` instead.
    pub fn block(&mut self) -> Result<Block<'a>, ParseError<'a>> {
        let mut statements = Vec::new();

        while let Some(t) = self.lexer.peek().and_then(|v| v.as_ref().ok()) {
            if t.token.kind() == TokenKind::Symbol(Symbol::Return) {
                statements.push(Statement::Return(self.return_stat()?));
                break;
            }

            if Self::TERMINATORS.contains(&t.token.kind()) {
                break;
            }

            statements.push(self.statement()?);
        }

        Ok(Block { statements })
    }

    fn empty_stat(&mut self) -> Result<EmptyStat<'a>, ParseError<'a>> {
        let semi = self.expect(Symbol::Semicolon)?;
        Ok(EmptyStat(semi))
    }

    fn block_stat(&mut self) -> Result<BlockStat<'a>, ParseError<'a>> {
        let do_ = self.expect(Symbol::Do)?;
        let block = Box::new(self.block()?);
        let end = self.expect(Symbol::End)?;
        Ok(BlockStat { do_, block, end })
    }

    fn while_stat(&mut self) -> Result<WhileStat<'a>, ParseError<'a>> {
        let was_inside_loop = self.is_inside_loop;
        self.is_inside_loop = true;

        let stat = WhileStat {
            while_: self.expect(Symbol::While)?,
            condition: Box::new(self.expr()?),
            do_: self.expect(Symbol::Do)?,
            block: Box::new(self.block()?),
            end: self.expect(Symbol::End)?,
        };

        self.is_inside_loop = was_inside_loop;

        Ok(stat)
    }

    fn generic_for(
        &mut self,
        for_: TokenReference<'a>,
        names: Punctuated<'a, Name<'a>>,
    ) -> Result<GenericFor<'a>, ParseError<'a>> {
        Ok(GenericFor {
            for_,
            names,
            in_: self.expect(Symbol::In)?,
            exprs: self.punctuated(Symbol::Comma, |s| s.expr().map(Box::new))?,
            do_: self.expect(Symbol::Do)?,
            block: Box::new(self.block()?),
            end: self.expect(Symbol::End)?,
        })
    }

    fn numerical_for(
        &mut self,
        for_: TokenReference<'a>,
        mut names: Punctuated<'a, Name<'a>>,
    ) -> Result<NumericalFor<'a>, ParseError<'a>> {
        Ok(NumericalFor {
            for_,
            name: names.pairs.remove(0).0,
            assign: self.expect(Symbol::Assign)?,
            from: Box::new(self.expr()?),
            comma: self.expect(Symbol::Comma)?,
            to: Box::new(self.expr()?),
            step: lookahead!(self {
                Symbol::Comma => {
                    let comma = self.expect(Symbol::Comma)?;
                    let expr = Box::new(self.expr()?);
                    Some((comma, expr))
                },
                _ => None,
            }),
            do_: self.expect(Symbol::Do)?,
            block: Box::new(self.block()?),
            end: self.expect(Symbol::End)?,
        })
    }

    fn for_stat(&mut self) -> Result<ForStat<'a>, ParseError<'a>> {
        let was_inside_loop = self.is_inside_loop;
        self.is_inside_loop = true;

        let for_ = self.expect(Symbol::For)?;

        let names = self.punctuated(Symbol::Comma, Self::name)?;

        let stat = if names.pairs.len() > 1 {
            self.generic_for(for_, names).map(ForStat::Generic)?
        } else {
            lookahead!(self {
                Symbol::In => {
                    self.generic_for(for_, names).map(ForStat::Generic)?
                },
                Symbol::Assign => {
                    self.numerical_for(for_, names).map(ForStat::Numerical)?
                },
            })
        };

        self.is_inside_loop = was_inside_loop;

        Ok(stat)
    }

    fn return_stat(&mut self) -> Result<ReturnStat<'a>, ParseError<'a>> {
        let return_ = self.expect(Symbol::Return)?;

        let next = self.lexer.peek().and_then(|v| v.as_ref().ok());
        let has_expr = next
            .filter(|t| !Self::TERMINATORS.contains(&t.token.kind()))
            .is_some();

        let exprs = if has_expr {
            self.punctuated(Symbol::Comma, |s| s.expr().map(Box::new))?
        } else {
            Punctuated { pairs: Vec::new() }
        };

        let semi = lookahead!(self {
            Symbol::Semicolon => {
                self.expect(Symbol::Semicolon).map(Some)?
            },
            _ => None,
        });

        Ok(ReturnStat {
            return_,
            exprs,
            semi,
        })
    }

    fn break_stat(&mut self) -> Result<BreakStat<'a>, ParseError<'a>> {
        let stat = self.expect(Symbol::Break).map(BreakStat)?;
        if self.is_inside_loop {
            Ok(stat)
        } else {
            Err(ParseError::BreakOutsideLoop { stat })
        }
    }

    /// Parses a single statement.
    pub fn statement(&mut self) -> Result<Statement<'a>, ParseError<'a>> {
        lookahead!(self {
            Symbol::Semicolon => self.empty_stat().map(Statement::Empty),
            Symbol::Do => self.block_stat().map(Statement::Block),
            Symbol::While => self.while_stat().map(Statement::While),
            Symbol::For => self.for_stat().map(Statement::For),
            Symbol::Repeat => self.repeat_stat().map(Statement::Repeat),
            Symbol::Return => self.return_stat().map(Statement::Return),
            Symbol::Break => self.break_stat().map(Statement::Break),
            Symbol::Function => self.function_declaration(None).map(Statement::FunctionDeclaration),
            Symbol::DoubleColon => self.label_stat().map(Statement::Label),
            Symbol::Goto => self.goto_stat().map(Statement::Goto),
            Symbol::If => self.if_stat().map(Statement::If),
            &[TokenKind::Symbol(Symbol::RoundBracketLeft), TokenKind::Ident][..] => {
                let expr = self.prefix_expr()?;
                match expr {
                    PrefixExpr::Var(var) => self.assignment(var).map(Statement::Assignment),
                    PrefixExpr::Call(call) => Ok(Statement::FunctionCall(call)),
                    PrefixExpr::Parenthesized(expr) => Err(ParseError::StatementExpected { expr })
                }
            },
            Symbol::Local => self.local(),
        })
    }

    fn var(&mut self) -> Result<Var<'a>, ParseError<'a>> {
        match self.prefix_expr()? {
            PrefixExpr::Var(v) => Ok(v),
            expr => Err(ParseError::VarExpected { expr }),
        }
    }

    fn varlist(&mut self, first: Var<'a>) -> Result<Punctuated<'a, Var<'a>>, ParseError<'a>> {
        let mut first = (first, None);
        let list = lookahead!(self {
            Symbol::Comma => {
                first.1 = self.expect(Symbol::Comma).map(Some)?;
                let mut rest = self.punctuated(Symbol::Comma, |s| s.var())?;
                rest.pairs.insert(0, first);
                rest
            },
            _ => Punctuated { pairs: vec![first] },
        });
        Ok(list)
    }

    fn assignment(&mut self, first: Var<'a>) -> Result<AssignmentStat<'a>, ParseError<'a>> {
        let vars = self.varlist(first)?;
        let assign = self.expect(Symbol::Assign)?;
        let exprs = self.punctuated(Symbol::Comma, |s| s.expr().map(Box::new))?;
        Ok(AssignmentStat {
            vars,
            assign,
            exprs,
        })
    }

    fn local(&mut self) -> Result<Statement<'a>, ParseError<'a>> {
        let local = self.expect(Symbol::Local)?;

        lookahead!(self {
            Symbol::Function => {
                self.function_declaration(Some(local)).map(Statement::FunctionDeclaration)
            },

            _ => self.local_declaration(local).map(Statement::LocalDeclaration),
        })
    }

    fn local_declaration(
        &mut self,
        local: TokenReference<'a>,
    ) -> Result<LocalDeclarationStat<'a>, ParseError<'a>> {
        let names = self.punctuated(Symbol::Comma, |s| s.name())?;

        let definition = lookahead!(self {
            Symbol::Assign => {
                let assign = self.expect(Symbol::Assign)?;
                let exprs = self.punctuated(
                    Symbol::Comma,
                    |s| s.expr().map(Box::new)
                )?;

                Some(LocalDefinition { assign, exprs })
            },
            _ => None,
        });

        Ok(LocalDeclarationStat {
            local,
            names,
            definition,
        })
    }

    fn function_declaration(
        &mut self,
        local: Option<TokenReference<'a>>,
    ) -> Result<FunctionDeclarationStat<'a>, ParseError<'a>> {
        let function = self.expect(Symbol::Function)?;

        Ok(match local {
            Some(local) => {
                let name = self.name()?;
                let body = self.function_body()?;

                FunctionDeclarationStat::Local {
                    local,
                    function,
                    name,
                    body,
                }
            }

            None => {
                let name = self.function_name()?;
                let body = self.function_body()?;

                FunctionDeclarationStat::Nonlocal {
                    function,
                    name,
                    body,
                }
            }
        })
    }

    fn function_name(&mut self) -> Result<FunctionName<'a>, ParseError<'a>> {
        let mut name = self.punctuated(Symbol::Period, |s| s.name())?;

        Ok(lookahead!(self {
            Symbol::Colon => {
                let colon = self.expect(Symbol::Colon)?;
                let method = self.name()?;

                FunctionName::Method {
                    receiver: name,
                    colon,
                    method
                }
            },

            _ => if name.pairs.len() == 1 {
                FunctionName::PlainName(name.pairs.remove(0).0)
            } else {
                FunctionName::Indexed(name)
            },
        }))
    }

    fn function_body(&mut self) -> Result<FunctionBody<'a>, ParseError<'a>> {
        let was_inside_loop = self.is_inside_loop;
        self.is_inside_loop = false;

        let mut params = Vec::new();
        let opening = self.expect(Symbol::RoundBracketLeft)?;

        let mut vararg = None;

        let closing = lookahead!(self {
            Symbol::RoundBracketRight => self.expect(Symbol::RoundBracketRight)?,
            Symbol::TriplePeriod => {
                vararg.replace(self.vararg()?);

                self.expect(Symbol::RoundBracketRight)?
            },
            _ => {
                params.push((self.name()?, None));

                loop {
                    lookahead!(self {
                        Symbol::Comma => {
                            params.last_mut().unwrap().1.replace(self.expect(Symbol::Comma)?);

                            lookahead!(self {
                                Symbol::TriplePeriod => {
                                    vararg.replace(self.vararg()?);
                                    break self.expect(Symbol::RoundBracketRight)?;
                                },
                                _ => params.push((self.name()?, None)),
                            });
                        },
                        Symbol::RoundBracketRight => break self.expect(Symbol::RoundBracketRight)?,
                    });
                }
            },
        });

        let block = Box::new(self.block()?);
        let end = self.expect(Symbol::End)?;

        let params = ParenthesizedList {
            brackets: Brackets(opening, closing),
            list: Punctuated { pairs: params },
        };

        self.is_inside_loop = was_inside_loop;

        Ok(FunctionBody {
            params,
            vararg,
            block,
            end,
        })
    }

    fn vararg(&mut self) -> Result<Vararg<'a>, ParseError<'a>> {
        self.expect(Symbol::TriplePeriod).map(Vararg)
    }

    fn function_expr(&mut self) -> Result<FunctionExpr<'a>, ParseError<'a>> {
        let function = self.expect(Symbol::Function)?;
        let body = self.function_body()?;

        Ok(FunctionExpr { function, body })
    }

    fn repeat_stat(&mut self) -> Result<RepeatStat<'a>, ParseError<'a>> {
        let was_inside_loop = self.is_inside_loop;
        self.is_inside_loop = true;

        let repeat = self.expect(Symbol::Repeat)?;
        let block = Box::new(self.block()?);
        let until = self.expect(Symbol::Until)?;
        let condition = self.expr()?;

        self.is_inside_loop = was_inside_loop;

        Ok(RepeatStat {
            repeat,
            block,
            until,
            condition,
        })
    }

    fn label_stat(&mut self) -> Result<LabelStat<'a>, ParseError<'a>> {
        let preceding = self.expect(Symbol::DoubleColon)?;
        let name = self.name()?;
        let following = self.expect(Symbol::DoubleColon)?;

        Ok(LabelStat {
            preceding,
            name,
            following,
        })
    }

    fn goto_stat(&mut self) -> Result<GotoStat<'a>, ParseError<'a>> {
        let goto = self.expect(Symbol::Goto)?;
        let label = self.name()?;

        Ok(GotoStat { goto, label })
    }

    fn if_stat(&mut self) -> Result<IfStat<'a>, ParseError<'a>> {
        let if_ = self.expect(Symbol::If)?;
        let condition = self.expr()?;
        let then = self.expect(Symbol::Then)?;
        let block = Box::new(self.block()?);

        let mut elseifs = Vec::new();

        loop {
            lookahead!(self {
                Symbol::ElseIf => {
                    elseifs.push(self.else_if()?);
                },

                _ => break,
            })
        }

        let else_ = lookahead!(self {
            Symbol::Else => Some(self.else_()?),
            _ => None,
        });

        let end = self.expect(Symbol::End)?;

        Ok(IfStat {
            if_,
            condition,
            then,
            block,
            elseifs,
            else_,
            end,
        })
    }

    fn else_if(&mut self) -> Result<ElseIf<'a>, ParseError<'a>> {
        let elseif = self.expect(Symbol::ElseIf)?;
        let condition = self.expr()?;
        let then = self.expect(Symbol::Then)?;
        let block = self.block()?;

        Ok(ElseIf {
            elseif,
            condition,
            then,
            block,
        })
    }

    fn else_(&mut self) -> Result<Else<'a>, ParseError<'a>> {
        let else_ = self.expect(Symbol::Else)?;
        let block = self.block()?;

        Ok(Else { else_, block })
    }
}