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>, } fn token_is_not_comment(a: &Result) -> 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, 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, 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 { 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, 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 { Ok(self .get_real(|token| matches!(token, Token::Semicolon), "a semicolon")? .1) } fn ask_ident(&mut self) -> Result, 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, 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, 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, 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, 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 { 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( mut f: impl FnMut() -> Result, ParserError>, ) -> Result, 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 { Parser::new(source).parse() } #[derive(thiserror::Error, Debug)] pub enum ParserError { // expected, got #[error("Unexpected `{_1}`, expected {_0}")] Unexpected(String, Spanned), #[error("Unexpected end of file")] UnexpectedEOF, #[error("please stop.")] PleaseStopParsingUse, }