use super::tokens::Kind;
use crate::ast::token_range::WithToken;
use crate::ast::Ident;
use crate::data::Diagnostic;
use crate::syntax::parser::ParsingContext;
use crate::{SrcPos, TokenId};
pub fn parse_optional<F, R>(
ctx: &mut ParsingContext<'_>,
keyword: Kind,
parse_fun: F,
) -> ParseResult<Option<R>>
where
F: FnOnce(&mut ParsingContext<'_>) -> ParseResult<R>,
{
let optional = {
if ctx.stream.skip_if_kind(keyword) {
Some(parse_fun(ctx)?)
} else {
None
}
};
Ok(optional)
}
pub fn check_end_identifier_mismatch<T: std::fmt::Display + std::cmp::PartialEq>(
ctx: &mut ParsingContext<'_>,
ident: &WithToken<T>,
end_ident: Option<WithToken<T>>,
) -> Option<TokenId> {
if let Some(end_ident) = end_ident {
if ident.item == end_ident.item {
return Some(end_ident.token);
} else {
ctx.diagnostics.push(Diagnostic::syntax_error(
end_ident.pos(ctx),
format!("End identifier mismatch, expected {}", ident.item),
));
}
}
None
}
pub fn check_label_identifier_mismatch(
ctx: &mut ParsingContext<'_>,
label: Option<&Ident>,
end_ident: Option<Ident>,
) -> Option<SrcPos> {
if let Some(ident) = label {
if let Some(end_ident) = end_ident {
if ident.item == end_ident.item {
return Some(end_ident.pos(ctx).clone());
} else {
ctx.diagnostics.push(Diagnostic::syntax_error(
end_ident.pos(ctx),
format!("End label mismatch, expected {}", ident.item),
));
}
}
} else if let Some(end_ident) = end_ident {
ctx.diagnostics.push(Diagnostic::syntax_error(
end_ident.pos(ctx),
format!(
"End label '{}' found for unlabeled statement",
end_ident.item
),
));
}
None
}
pub type ParseResult<T> = Result<T, Diagnostic>;