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, 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); match self.tokens.peek()?.0 { Token::Comma => { self.eat(); } Token::RightParen => {} _ => return Err(self.expected("a comma or closing parentheses")), }; } 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::::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); match self.tokens.peek()?.0 { Token::Comma => { self.eat(); } Token::RightCurly => {} _ => return Err(self.expected("a comma or closing curly braces")), }; } 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, } } match self.tokens.peek()?.0 { Token::Comma => { self.eat(); } Token::RightCurly => {} _ => return Err(self.expected("a comma or closing curly braces")), } 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("???")) } }