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

245 lines
7.7 KiB
Rust

mod enumeration;
mod expr;
mod interface;
mod structure;
mod types;
use logos::{Lexer, Logos};
use crate::{
ast::{IDLModule, Item, ItemAlias, ItemConstant, UseDecl},
lexer::{Ident, Span, Spanned, Token},
};
use std::iter::Iterator;
pub struct TokenIterator<'a> {
lexer: Lexer<'a, Token>,
peeked: Option<Option<Token>>,
}
fn token_is_not_comment(a: &Result<Token, ()>) -> bool {
!matches!(a, Err(_) | Ok(Token::Comment(..)))
}
impl<'a> TokenIterator<'a> {
pub fn new(src: &'a str) -> Self {
let lexer = Token::lexer(src);
Self {
lexer,
peeked: None,
}
}
pub fn next(&mut self) -> Result<Spanned<Token>, ParserError> {
let n = match self.peeked.take() {
Some(thing) => thing,
None => self.lexer.find(token_is_not_comment).and_then(Result::ok),
};
let nxt = n.map(|token| Spanned(token, Span(self.lexer.span())));
// println!("[NEXT] {:#?}", nxt);
nxt.ok_or(ParserError::UnexpectedEOF)
}
fn _peek(&mut self) -> Option<&Token> {
self.peeked
.get_or_insert_with(|| self.lexer.find(token_is_not_comment).and_then(Result::ok))
.as_ref()
}
pub fn peek(&mut self) -> Result<Spanned<&Token>, ParserError> {
let span = Span(self.lexer.span());
let peek = self._peek().map(|token| Spanned(token, span));
// println!("[PEEK] {:#?}", peek);
peek.ok_or(ParserError::UnexpectedEOF)
}
pub fn current(&self) -> Spanned<String> {
Spanned(self.lexer.slice().to_owned(), self.span())
}
pub fn span(&self) -> Span {
Span(self.lexer.span())
}
}
pub(crate) struct Parser<'a> {
tokens: TokenIterator<'a>,
}
impl<'a> Parser<'a> {
pub fn new(src: &'a str) -> Self {
Self {
tokens: TokenIterator::new(src),
}
}
fn eat(&mut self) {
let _ = self.tokens.next();
}
fn get_real(
&mut self,
matcher: impl Fn(&Token) -> bool,
expected: &'static str,
) -> Result<Spanned<Token>, ParserError> {
if matcher(self.tokens.peek()?.0) {
self.tokens.next()
} else {
Err(self.expected(expected))
}
}
fn expected(&self, expected: &'static str) -> ParserError {
ParserError::Unexpected(expected.to_owned(), self.tokens.current())
}
fn semi(&mut self) -> Result<Span, ParserError> {
Ok(self
.get_real(|token| matches!(token, Token::Semicolon), "a semicolon")?
.1)
}
fn ask_ident(&mut self) -> Result<Spanned<String>, ParserError> {
Ok(
match self.get_real(
|token| {
matches!(
token,
Token::Ident(Ident::Other(_) | Ident::Underscore) | Token::NumberSuffix(_)
)
},
"an identifier",
)? {
Spanned(Token::Ident(Ident::Other(ident)), span) => Spanned(ident, span),
Spanned(Token::Ident(Ident::Underscore), span) => Spanned("_".to_owned(), span),
Spanned(Token::NumberSuffix(suffix), span) => Spanned(suffix.to_string(), span),
_ => unreachable!(),
},
)
}
fn ask_alias(&mut self) -> Result<Spanned<ItemAlias>, ParserError> {
let Spanned(_, kSp) = self.get_real(
|token| matches!(token, Token::Ident(Ident::Alias)),
"`Alias`",
)?;
let Spanned(name, nSp) = self.ask_ident()?;
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
let Spanned(referree, rSp) = self.ask_type()?;
Ok(Spanned::new(
ItemAlias { name, referree },
[kSp, nSp, eqSp, rSp, self.semi()?],
))
}
fn ask_constant(&mut self) -> Result<Spanned<ItemConstant>, ParserError> {
let Spanned(_, kSp) = self.get_real(
|token| matches!(token, Token::Ident(Ident::Constant)),
"`Constant`",
)?;
let Spanned(name, nSp) = self.ask_ident()?;
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
let Spanned(expr, exprSp) = self.ask_expr()?;
Ok(Spanned::new(
ItemConstant { name, expr },
[kSp, nSp, eqSp, exprSp, self.semi()?],
))
}
fn ask_item(&mut self) -> Result<Spanned<Item>, ParserError> {
Ok(match self.tokens.peek()?.0 {
Token::Ident(Ident::Other(_)) => {
Err(self.expected("a keyword, not just an identifier"))?
}
Token::Ident(keyword) => match keyword {
Ident::Interface => self.ask_interface()?.map(Item::Interface),
Ident::Structure => self.ask_structure()?.map(Item::Structure),
Ident::Alias => self.ask_alias()?.map(Item::Alias),
Ident::Constant => self.ask_constant()?.map(Item::Constant),
Ident::Function => self.ask_function()?.map(Item::Function),
Ident::Enumeration => self.ask_enumeration()?.map(Item::Enumeration),
_ => Err(self.expected("an item denoting keyword (Interface, Structure, Alias, Constant, Function, Enumeration)"))?,
},
_ => Err(self.expected("a keyword"))?,
})
}
fn ask_use(&mut self) -> Result<Spanned<UseDecl>, ParserError> {
let Spanned(_, span) = {
match self.tokens.peek()? {
Spanned(Token::Ident(Ident::Use), _) => Ok(self.tokens.next()?),
_ => Err(ParserError::PleaseStopParsingUse),
}
}?;
let mut path = (self.ask_ident()?.0, None);
if let Token::Dot = self.tokens.peek()?.0 {
self.eat();
path.1 = Some(self.ask_ident()?.0);
}
Ok(Spanned::new(UseDecl { path }, [span, self.semi()?]))
}
pub fn parse(mut self) -> Result<IDLModule, ParserError> {
Ok(IDLModule {
name: {
self.get_real(
|token| matches!(token, Token::Ident(Ident::Module)),
"the `Module` keyword",
)?;
let name = self.ask_ident()?.0;
self.semi()?;
name
},
uses: {
let mut real = vec![];
loop {
let r = self.ask_use();
match r {
Ok(Spanned(a, _)) => real.push(a),
Err(ParserError::UnexpectedEOF) => return Err(ParserError::UnexpectedEOF),
Err(ParserError::PleaseStopParsingUse) => break,
Err(unexpected @ ParserError::Unexpected(..)) => return Err(unexpected),
}
}
Ok(real)
}?,
items: fill_while(|| self.ask_item())?,
})
}
}
fn fill_while<T>(
mut f: impl FnMut() -> Result<Spanned<T>, ParserError>,
) -> Result<Vec<T>, ParserError> {
let mut real = vec![];
loop {
match f() {
Ok(Spanned(next, _)) => real.push(next),
Err(unexpected @ ParserError::Unexpected(..)) => return Err(unexpected),
Err(ParserError::UnexpectedEOF) => break,
Err(ParserError::PleaseStopParsingUse) => unreachable!(),
}
}
Ok(real)
}
pub fn parse(source: &str) -> Result<IDLModule, ParserError> {
Parser::new(source).parse()
}
#[derive(thiserror::Error, Debug)]
pub enum ParserError {
// expected, got
#[error("Unexpected `{_1}`, expected {_0}")]
Unexpected(String, Spanned<String>),
#[error("Unexpected end of file")]
UnexpectedEOF,
#[error("please stop.")]
PleaseStopParsingUse,
}