ableos_userland/programs/aidl/src/parser.rs

151 lines
4.2 KiB
Rust

use logos::{Logos, SpannedIter};
use crate::{
ast::{IDLModule, Item, ItemInterface, ItemType, UseDecl},
lexer::{Span, Spanned, Token, Ident},
};
use std::{
iter::{Iterator, Peekable, Filter},
ops::Range,
};
type Wtf<'a> = Peekable<
Filter<SpannedIter<'a, Token>, Box<dyn Fn(&(Result<Token, ()>, Range<usize>)) -> bool>>,
>;
struct TokenIterator<'a> {
spanned: Wtf<'a>,
}
fn token_is_not_comment((ref a, ..): &(Result<Token, ()>, Range<usize>)) -> bool {
!matches!(a, Err(_) | Ok(Token::Comment(..)))
}
impl<'a> TokenIterator<'a> {
pub fn new(src: &'a str) -> Self {
let spanned = Token::lexer(src)
.spanned()
.filter(
Box::new(token_is_not_comment) as Box<dyn Fn(&(Result<Token, ()>, Range<usize>)) -> bool>,
)
.peekable();
Self { spanned }
}
pub fn next(&mut self) -> Option<Spanned<Token>> {
let nxt = self
.spanned
.next()
.and_then(|(token, span)| Some(Spanned(token.ok()?, Span(span))));
println!("[NEXT] {:#?}", nxt);
nxt
}
pub fn peek(&mut self) -> Option<Spanned<&Token>> {
let peek = self
.spanned
.peek()
.and_then(|(token, span)| Some(Spanned(token.as_ref().ok()?, Span(span.clone()))));
println!("[PEEK] {:#?}", peek);
peek
}
}
pub struct Parser<'a> {
tokens: TokenIterator<'a>,
}
impl<'a> Parser<'a> {
pub fn new(src: &'a str) -> Self {
Self {
tokens: TokenIterator::new(src),
}
}
fn get_real(&mut self, matcher: impl Fn(&Token) -> bool) -> Option<Spanned<Token>> {
if matcher(self.tokens.peek()?.0) {
self.tokens.next()
} else {
None
}
}
fn semi(&mut self) -> Option<Span> {
Some(self.get_real(|token| matches!(token, Token::Semicolon))?.1)
}
fn ask_ident(&mut self) -> Option<Spanned<String>> {
Some(crate::unwrap_match!(
self.get_real(|token| matches!(token, Token::Ident(Ident::Other(_))))?,
Spanned(Token::Ident(Ident::Other(ident)), span) =>
Spanned(ident, span)
))
}
fn ask_interface(&mut self) -> Option<Spanned<ItemInterface>> {
let Spanned(_, kSp) =
self.get_real(|token| matches!(token, Token::Ident(Ident::Interface)))?;
let Spanned(ident, iSp) = self.ask_ident()?;
Some(Spanned::new(
ItemInterface {
name: ident,
functions: vec![],
},
[kSp, iSp, self.semi()?],
))
}
fn ask_typealias(&mut self) -> Option<Spanned<ItemType>> {
let Spanned(_, kSp) =
self.get_real(|token| matches!(token, Token::Ident(Ident::Type)))?;
let Spanned(name, nSp) = self.ask_ident()?;
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals))?;
let Spanned(referree, rSp) = self.ask_ident()?;
Some(Spanned::new(
ItemType { name, referree },
[kSp, nSp, eqSp, rSp, self.semi()?],
))
}
fn ask_item(&mut self) -> Option<Spanned<Item>> {
Some(match self.tokens.peek()?.0 {
Token::Ident(Ident::Other(_)) => None?,
Token::Ident(keyword) => match keyword {
Ident::Interface => self.ask_interface()?.map(Item::Interface),
Ident::Type => self.ask_typealias()?.map(Item::Type),
_ => None?,
},
_ => None?,
})
}
fn ask_use(&mut self) -> Option<Spanned<UseDecl>> {
let Spanned(_, kSp) =
self.get_real(|token| matches!(token, Token::Ident(Ident::Use)))?;
let Spanned(name, nSp) = self.ask_ident()?;
Some(Spanned::new(
UseDecl { module: name },
[kSp, nSp, self.semi()?],
))
}
pub fn parse(mut self) -> IDLModule {
IDLModule {
uses: fill_while(|| self.ask_use()),
items: fill_while(|| self.ask_item()),
}
}
}
fn fill_while<T>(mut f: impl FnMut() -> Option<Spanned<T>>) -> Vec<T> {
let mut real = vec![];
while let Some(Spanned(t, _)) = f() {
real.push(t);
}
real
}