use crate::lexer::token::Span;
use crate::lexer::token::TokenKind;
use crate::parser::ast::utils::CommaSeparated;
use crate::parser::ast::Ending;
use crate::parser::error;
use crate::parser::error::ParseResult;
use crate::parser::state::State;
pub fn skip_ending(state: &mut State) -> ParseResult<Ending> {
let current = state.stream.current();
if current.kind == TokenKind::CloseTag {
state.stream.next();
Ok(Ending::CloseTag(current.span))
} else if current.kind == TokenKind::SemiColon {
state.stream.next();
Ok(Ending::Semicolon(current.span))
} else {
Err(error::unexpected_token(vec![";".to_string()], current))
}
}
pub fn skip_semicolon(state: &mut State) -> ParseResult<Span> {
let current = state.stream.current();
if current.kind == TokenKind::SemiColon {
state.stream.next();
Ok(current.span)
} else {
Err(error::unexpected_token(vec!["`;`".to_string()], current))
}
}
pub fn skip_left_brace(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::LeftBrace)
}
pub fn skip_right_brace(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::RightBrace)
}
pub fn skip_left_parenthesis(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::LeftParen)
}
pub fn skip_right_parenthesis(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::RightParen)
}
pub fn skip_left_bracket(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::LeftBracket)
}
pub fn skip_right_bracket(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::RightBracket)
}
pub fn skip_double_arrow(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::DoubleArrow)
}
pub fn skip_double_colon(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::DoubleColon)
}
pub fn skip_colon(state: &mut State) -> ParseResult<Span> {
skip(state, TokenKind::Colon)
}
pub fn skip(state: &mut State, kind: TokenKind) -> ParseResult<Span> {
let current = state.stream.current();
if current.kind == kind {
let end = current.span;
state.stream.next();
Ok(end)
} else {
Err(error::unexpected_token(vec![kind.to_string()], current))
}
}
pub fn skip_any_of(state: &mut State, kinds: &[TokenKind]) -> ParseResult<Span> {
let current = state.stream.current();
if kinds.contains(¤t.kind) {
let end = current.span;
state.stream.next();
Ok(end)
} else {
Err(error::unexpected_token(
kinds.iter().map(|kind| kind.to_string()).collect(),
current,
))
}
}
pub fn parenthesized<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
) -> ParseResult<(Span, T, Span)> {
let left_parenthesis = skip_left_parenthesis(state)?;
let inner = func(state)?;
let right_parenthesis = skip_right_parenthesis(state)?;
Ok((left_parenthesis, inner, right_parenthesis))
}
pub fn braced<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
) -> ParseResult<(Span, T, Span)> {
let left_brace = skip_left_brace(state)?;
let inner = func(state)?;
let right_brace = skip_right_brace(state)?;
Ok((left_brace, inner, right_brace))
}
pub fn semicolon_terminated<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
) -> ParseResult<(Span, T)> {
let inner = func(state)?;
let semicolon = skip_semicolon(state)?;
Ok((semicolon, inner))
}
pub fn comma_separated<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
until: TokenKind,
) -> ParseResult<CommaSeparated<T>> {
let mut inner: Vec<T> = vec![];
let mut commas: Vec<Span> = vec![];
let mut current = state.stream.current();
while current.kind != until {
inner.push(func(state)?);
current = state.stream.current();
if current.kind != TokenKind::Comma {
break;
}
commas.push(current.span);
state.stream.next();
current = state.stream.current();
}
Ok(CommaSeparated { inner, commas })
}
pub fn comma_separated_no_trailing<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
until: TokenKind,
) -> ParseResult<CommaSeparated<T>> {
let mut inner: Vec<T> = vec![];
let mut commas: Vec<Span> = vec![];
let mut current = state.stream.current();
while current.kind != until {
inner.push(func(state)?);
current = state.stream.current();
if current.kind != TokenKind::Comma {
break;
}
if state.stream.peek().kind == until {
break;
}
commas.push(current.span);
state.stream.next();
current = state.stream.current();
}
Ok(CommaSeparated { inner, commas })
}
pub fn at_least_one_comma_separated_no_trailing<T>(
state: &mut State,
func: &(dyn Fn(&mut State) -> ParseResult<T>),
) -> ParseResult<CommaSeparated<T>> {
let mut inner: Vec<T> = vec![];
let mut commas: Vec<Span> = vec![];
loop {
inner.push(func(state)?);
let current = state.stream.current();
if current.kind != TokenKind::Comma {
break;
}
commas.push(current.span);
state.stream.next();
}
Ok(CommaSeparated { inner, commas })
}