ableos_userland/programs/aidl/src/parser/enumeration.rs

146 lines
5.9 KiB
Rust

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);
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::<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);
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("???"))
}
}