use std::rc::Rc;
use crate::error::{LuaError, Result};
use crate::lexer::{Pos, Spanned, Token, Tokenizer};
macro_rules! tok_expect {
( $self:ident, $pat:pat ) => {{
let (pos, tok) = $self.tok_next()?.into();
if !matches!(tok, $pat) {
return err!(
&*$self.source,
pos,
crate::error::LuaError::UnexpectedToken(tok)
);
}
pos
}};
}
mod assignment;
mod block;
mod chunk;
mod expression;
mod r#for;
mod function;
mod r#if;
mod local;
mod prefix_exp;
mod repeat;
mod statement;
mod table;
mod r#while;
pub use assignment::{Ass, Var};
pub use block::Block;
pub use chunk::Chunk;
pub use expression::Exp;
pub use function::Func;
pub use local::{Attr, Local};
pub use prefix_exp::PrefixExp;
pub use r#for::{For, ForGen, ForNum};
pub use r#if::If;
pub use r#while::While;
pub use repeat::Repeat;
pub use statement::Stat;
pub use table::TableField;
pub struct Parser<'a> {
tokens: Tokenizer<'a>,
peek: Option<Option<Spanned<Token>>>,
source: Rc<Vec<u8>>,
exp_depth: usize,
scope_depth: usize,
}
const MAX_ARGS: usize = 200;
const MAX_ASSIGN: usize = 200;
const MAX_EXP: usize = 200;
const MAX_SCOPE: usize = 200;
impl<'a> Parser<'a> {
pub fn parse(input: &'a [u8], source: Rc<Vec<u8>>) -> Result<Chunk> {
let mut parser = Self {
tokens: Tokenizer::read(input, source.clone()),
peek: None,
source,
exp_depth: 0,
scope_depth: 0,
};
let chunk = parser.parse_chunk()?;
if let Ok((pos, tok)) = parser.tok_next().map(Into::into) {
return err!(&*parser.source, pos, LuaError::UnexpectedToken(tok));
}
assert!(parser.exp_depth == 0);
assert!(parser.scope_depth == 0);
Ok(chunk)
}
fn tok_next(&mut self) -> Result<Spanned<Token>> {
let opt = match self.peek.take() {
Some(opt) => opt,
None => self.tokens.read_token()?,
};
match opt {
Some(tok) => Ok(tok),
None => err!(
&*self.source,
self.tokens.last_pos(),
LuaError::UnexpectedEof
),
}
}
fn tok_next_opt(&mut self) -> Result<Option<Spanned<Token>>> {
match self.peek.take() {
Some(opt) => Ok(opt),
None => self.tokens.read_token(),
}
}
fn tok_ident(&mut self) -> Result<(Pos, String)> {
let (pos, tok) = self.tok_next()?.into();
match tok {
Token::Ident(ident) => Ok((pos, ident)),
tok => err!(&*self.source, pos, LuaError::UnexpectedToken(tok)),
}
}
fn tok_peek(&mut self) -> Result<&Spanned<Token>> {
if self.peek.is_none() {
self.peek = Some(self.tokens.read_token()?);
}
match self.peek.as_ref().unwrap() {
Some(tok) => Ok(tok),
None => err!(
&*self.source,
self.tokens.last_pos(),
LuaError::UnexpectedEof
),
}
}
fn tok_peek_opt(&mut self) -> Result<Option<&Spanned<Token>>> {
if self.peek.is_none() {
self.peek = Some(self.tokens.read_token()?);
}
Ok(self.peek.as_ref().unwrap().as_ref())
}
}