use std::rc::Rc;
use crate::ast::{Ass, Block, Exp, For, Func, If, Local, Parser, PrefixExp, Repeat, While};
use crate::error::{LuaError, Result};
use crate::lexer::{Pos, Spanned, Token};
use crate::vm::Literal;
pub enum Stat {
Nop,
Ass(Ass),
Call(Pos, PrefixExp, Vec<Exp>),
CallMethod(Pos, Box<PrefixExp>, String, Vec<Exp>),
Func(Option<PrefixExp>, String, Func),
LocalFunc(String, Func),
Local(Local),
Do(Block),
If(If),
Break(Pos),
While(While),
Repeat(Repeat),
For(For),
Goto(String, Pos),
Label(String, Pos),
}
impl<'a> Parser<'a> {
pub(super) fn parse_stat(&mut self) -> Result<Stat> {
Ok(match self.tok_peek()?.into() {
(_, Token::Semi) => {
self.tok_next()?;
Stat::Nop
}
(_, Token::Ident(_) | Token::ParO) => {
let prefix_exp = self.parse_prefix_exp()?;
match prefix_exp {
PrefixExp::Var(..) | PrefixExp::Index(..) => {
Stat::Ass(self.parse_ass(prefix_exp)?)
}
PrefixExp::Call(pos, func, args) => Stat::Call(pos, *func, args),
PrefixExp::CallMethod(pos, table, name, args) => {
Stat::CallMethod(pos, table, name, args)
}
PrefixExp::Par(_, pos) => {
return err!(self.source, pos, LuaError::UnexpectedToken(Token::ParO))
}
}
}
(_, Token::Local) => {
self.tok_next()?;
match self.tok_peek_opt()?.map(Into::into) {
Some((_, Token::Function)) => {
self.tok_next()?;
let (_, name) = self.tok_ident()?;
let func = self.parse_func()?;
Stat::LocalFunc(name, func)
}
_ => Stat::Local(self.parse_local()?),
}
}
(_, Token::Function) => {
self.tok_next()?;
let mut prefix = None;
let (pos_name, mut name) = self.tok_ident()?;
let mut is_method = false;
while !is_method {
match self.tok_peek_opt()?.map(Spanned::inner) {
Some(Token::Point) => {}
Some(Token::Colon) => {
is_method = true;
}
_ => break,
}
self.tok_next()?;
let (pos_ind, index) = self.tok_ident()?;
match prefix {
Some(pfx) => {
prefix = Some(PrefixExp::Index(
Box::new(pfx),
Box::new(Exp::Lit(
Literal::String(Rc::new(name.into_bytes())),
pos_name,
)),
pos_ind,
))
}
None => prefix = Some(PrefixExp::Var(name, pos_name)),
}
name = index;
}
let mut func = self.parse_func()?;
if is_method {
func.params.insert(0, "self".to_string());
}
Stat::Func(prefix, name, func)
}
(_, Token::Do) => {
self.tok_next()?;
let block = self.parse_block()?;
tok_expect!(self, Token::End);
Stat::Do(block)
}
(_, Token::If) => Stat::If(self.parse_if()?),
(pos, Token::Break) => {
self.tok_next()?;
Stat::Break(pos)
}
(_, Token::While) => Stat::While(self.parse_while()?),
(_, Token::Repeat) => Stat::Repeat(self.parse_repeat()?),
(_, Token::For) => Stat::For(self.parse_for()?),
(pos, Token::Goto) => {
self.tok_next()?;
let (_, label) = self.tok_ident()?;
Stat::Goto(label, pos)
}
(pos, Token::Ass) => {
self.tok_next()?;
let (_, label) = self.tok_ident()?;
tok_expect!(self, Token::Ass);
Stat::Label(label, pos)
}
(pos, tok) => return err!(&*self.source, pos, LuaError::UnexpectedToken(tok.clone())),
})
}
}