2023-05-05 11:21:24 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
ast::{EnumerationContent, EnumerationVariant, ItemEnumeration, Type},
|
|
|
|
lexer::{Ident, Spanned, Token},
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::{Parser, ParserError};
|
|
|
|
|
|
|
|
impl<'a> Parser<'a> {
|
|
|
|
pub fn ask_enumeration(&mut self) -> Result<Spanned<ItemEnumeration>, ParserError> {
|
|
|
|
let Spanned(_, span) = self.get_real(
|
|
|
|
|token| matches!(token, Token::Ident(Ident::Enumeration)),
|
|
|
|
"the `Enumeration` keyword",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let Spanned(Type { name, arguments }, _) = self.ask_type()?;
|
|
|
|
|
|
|
|
self.get_real(
|
|
|
|
|token| matches!(token, Token::LeftCurly),
|
|
|
|
"an opening curly brace",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let mut variants = vec![];
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Ident(Ident::Other(_)) => {
|
|
|
|
let Spanned(variant_name, _) = self.ask_ident()?;
|
|
|
|
|
|
|
|
let mut content = EnumerationContent::None;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::LeftParen => {
|
|
|
|
self.eat();
|
|
|
|
|
|
|
|
let mut tuple = vec![];
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Ident(Ident::Other(_)) => {
|
|
|
|
tuple.push(self.ask_type()?.0);
|
2023-05-06 15:57:45 +00:00
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Comma => {
|
|
|
|
self.eat();
|
|
|
|
}
|
|
|
|
Token::RightParen => {}
|
|
|
|
_ => return Err(self.expected("a comma or closing parentheses")),
|
2023-05-05 11:21:24 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
Token::RightParen => {
|
|
|
|
self.eat();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return Err(
|
|
|
|
self.expected("closing parentheses or a type")
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
content = EnumerationContent::Tuple(tuple);
|
|
|
|
}
|
|
|
|
Token::LeftCurly => {
|
|
|
|
self.eat();
|
|
|
|
|
|
|
|
let mut structure = HashMap::<String, Type>::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Ident(Ident::Other(_)) => {
|
|
|
|
let Spanned(field_name, _) = self.ask_ident()?;
|
|
|
|
|
|
|
|
self.get_real(
|
|
|
|
|token| matches!(token, Token::Colon),
|
|
|
|
"a colon",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
structure.insert(field_name, self.ask_type()?.0);
|
2023-05-06 15:57:45 +00:00
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Comma => {
|
|
|
|
self.eat();
|
|
|
|
}
|
|
|
|
Token::RightCurly => {}
|
|
|
|
_ => return Err(self.expected("a comma or closing curly braces")),
|
2023-05-05 11:21:24 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
Token::RightCurly => {
|
|
|
|
self.eat();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return Err(
|
|
|
|
self.expected("closing parentheses or a type")
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
content = EnumerationContent::Structure(structure);
|
|
|
|
}
|
|
|
|
Token::Equals => {
|
|
|
|
self.eat();
|
|
|
|
|
|
|
|
content = EnumerationContent::Value(self._ask_number_literal()?.0);
|
|
|
|
}
|
|
|
|
_ => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-06 15:57:45 +00:00
|
|
|
match self.tokens.peek()?.0 {
|
|
|
|
Token::Comma => {
|
|
|
|
self.eat();
|
|
|
|
}
|
|
|
|
Token::RightCurly => {}
|
|
|
|
_ => return Err(self.expected("a comma or closing curly braces")),
|
2023-05-05 11:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
variants.push(EnumerationVariant {
|
|
|
|
name: variant_name,
|
|
|
|
content,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Token::RightCurly => break,
|
|
|
|
_ => return Err(self.expected("a closing curly brace or a variant")),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Spanned(Token::RightCurly, _) = self.tokens.peek()? {
|
|
|
|
self.eat();
|
|
|
|
|
|
|
|
return Ok(Spanned(
|
|
|
|
ItemEnumeration {
|
|
|
|
name,
|
|
|
|
arguments,
|
|
|
|
variants,
|
|
|
|
},
|
|
|
|
span + self.tokens.span(),
|
|
|
|
));
|
|
|
|
};
|
|
|
|
|
|
|
|
Err(self.expected("???"))
|
|
|
|
}
|
|
|
|
}
|