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

260 lines
8.3 KiB
Rust

mod enumeration;
mod expr;
mod interface;
mod structure;
mod types;
use logos::{Lexer, Logos};
use crate::{
ast::{IDLModule, Item, ItemAlias, ItemConstant, ModulePath, UseDecl},
lexer::{Ident, Span, Spanned, Token},
};
use std::iter::Iterator;
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)),
"an identifier",
)? {
Spanned(Token::Ident(Ident::Other(ident)), span) => Spanned(ident, span),
Spanned(Token::Ident(Ident::Underscore), span) => Spanned("_".to_owned(), span),
_ => unreachable!(),
},
)
}
fn ask_modpath(
&mut self,
end: impl Fn(&Token) -> bool,
) -> Result<Spanned<ModulePath>, ParserError> {
let mut segments = vec![];
let mut in_path_seg = false;
let mut waiting_next_seg = true;
let mut span = Span::ZERO;
loop {
match self.tokens.next()? {
Spanned(Token::Ident(Ident::Other(ident)), span_span)
if !in_path_seg && waiting_next_seg =>
{
span += span_span;
segments.push(ident);
in_path_seg = true;
waiting_next_seg = false;
}
Spanned(Token::Dot, span_span) if in_path_seg && !waiting_next_seg => {
span += span_span;
waiting_next_seg = true;
in_path_seg = false;
}
v if end(&v.0) && (in_path_seg || !waiting_next_seg) => {
span += v.1;
break;
}
_ => return Err(self.expected("a path segment")),
}
}
Ok(Spanned(ModulePath { segments }, span))
}
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(_, kSp) = {
match self.tokens.peek()? {
Spanned(Token::Ident(Ident::Use), _) => Ok(self.tokens.next()?),
_ => Err(ParserError::PleaseStopParsingUse),
}
}?;
let Spanned(module, nSp) = self.ask_modpath(|token| matches!(token, Token::Semicolon))?;
Ok(Spanned::new(UseDecl { module }, [kSp, nSp]))
}
pub fn parse(mut self) -> Result<IDLModule, ParserError> {
Ok(IDLModule {
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,
}