forked from AbleOS/ableos_userland
245 lines
7.7 KiB
Rust
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,
|
|
}
|