use crate::ast::{
FilterMap, FilterType, Identifier, Params, RecordTypeDeclaration,
TypeExpr, Variant, VariantTypeDeclaration,
};
use super::{
ParseError, ParseResult, Parser,
meta::Meta,
token::{Keyword, Token},
};
impl Parser<'_, '_> {
pub(super) fn filter_map(&mut self) -> ParseResult<FilterMap> {
let (token, span) = self.next()?;
let filter_type = match token {
Token::Keyword(Keyword::FilterMap) => FilterType::FilterMap,
Token::Keyword(Keyword::Filter) => FilterType::Filter,
_ => {
return Err(ParseError::expected(
"`filtermap` or `filter`",
token,
span,
)
.into());
}
};
let ident = self.identifier()?;
let params = self.params()?;
let body = self.block()?;
Ok(FilterMap {
filter_type,
ident,
params,
body,
})
}
pub fn params(&mut self) -> ParseResult<Meta<Params>> {
let m = self.separated(
Token::RoundLeft,
Token::RoundRight,
Token::Comma,
Self::type_ident_field,
)?;
let id = m.id;
Ok(Meta {
id,
node: Params(m.node),
})
}
fn type_ident_field(
&mut self,
) -> ParseResult<(Meta<Identifier>, Meta<TypeExpr>)> {
let field_name = self.identifier()?;
self.take(Token::Colon)?;
let ty = self.type_expr()?;
Ok((field_name, ty))
}
pub fn type_parameters(&mut self) -> ParseResult<Vec<Meta<Identifier>>> {
let params = if self.peek_is(Token::SquareLeft) {
self.separated(
Token::SquareLeft,
Token::SquareRight,
Token::Comma,
Self::identifier,
)?
.node
} else {
Vec::new()
};
Ok(params)
}
pub(super) fn record_type_assignment(
&mut self,
) -> ParseResult<RecordTypeDeclaration> {
self.take(Token::Keyword(Keyword::Record))?;
let ident = self.identifier()?;
let type_params = self.type_parameters()?;
let record_type = self.record_type()?;
Ok(RecordTypeDeclaration {
ident,
type_params,
record_type,
})
}
pub(super) fn variant_declaration(
&mut self,
) -> ParseResult<VariantTypeDeclaration> {
self.take(Token::Keyword(Keyword::Variant))?;
let ident = self.identifier()?;
let type_params = self.type_parameters()?;
let variants = self.separated(
Token::CurlyLeft,
Token::CurlyRight,
Token::Comma,
Self::enum_variant,
)?;
Ok(VariantTypeDeclaration {
ident,
type_params,
variants,
})
}
fn enum_variant(&mut self) -> ParseResult<Variant> {
let ident = self.identifier()?;
let fields = if self.peek_is(Token::RoundLeft) {
self.separated(
Token::RoundLeft,
Token::RoundRight,
Token::Comma,
Self::type_expr,
)?
.node
} else {
Vec::new()
};
Ok(Variant { ident, fields })
}
}