#![allow(clippy::upper_case_acronyms)] pub mod combinator; mod peg_parser; mod test; use std::{cell::RefCell, fmt, rc::Rc}; use combinator::Span; #[cfg(test)] use crate::ast::{Block, Expression}; use crate::{ ast::{ASTItem, AST}, identifier::{Id, IdStore}, }; pub(crate) type StoreRef = Rc>>; pub struct Parser { id_store: StoreRef, use_combinator: bool, } impl Parser { pub(crate) fn new() -> Self { let id_store: IdStore = IdStore::new(); Self { id_store: Rc::new(RefCell::new(id_store)), use_combinator: true } } pub(crate) fn parse(&mut self, input: &str) -> Result { if self.use_combinator { self.parse_comb(input) } else { self.parse_peg(input) } } pub(crate) fn parse_peg(&mut self, input: &str) -> Result { peg_parser::schala_parser::program(input, self).map_err(ParseError::from_peg) } pub(crate) fn parse_comb(&mut self, input: &str) -> Result { let span = Span::new_extra(input, self.id_store.clone()); convert(input, combinator::program(span)) } #[cfg(test)] fn expression(&mut self, input: &str) -> Result { peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg) } #[cfg(test)] fn expression_comb(&mut self, input: &str) -> Result { let span = Span::new_extra(input, self.id_store.clone()); convert(input, combinator::expression(span)) } #[cfg(test)] fn block(&mut self, input: &str) -> Result { peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg) } #[cfg(test)] fn block_comb(&mut self, input: &str) -> Result { let span = Span::new_extra(input, self.id_store.clone()); convert(input, combinator::block(span)) } fn fresh(&mut self) -> Id { self.id_store.borrow_mut().fresh() } } fn convert<'a, O>(input: &'a str, result: combinator::ParseResult<'a, O>) -> Result { use nom::{error::VerboseError, Finish}; match result.finish() { Ok((rest, output)) => { if rest.fragment() != &"" { return Err(ParseError { location: Default::default(), msg: format!("Bad parse state, remaining text: `{}`", rest.fragment()), }); } Ok(output) } Err(err) => { let err = VerboseError { errors: err.errors.into_iter().map(|(sp, kind)| (*sp.fragment(), kind)).collect(), }; let msg = nom::error::convert_error(input, err); Err(ParseError { msg, location: (0).into() }) } } } /// Represents a parsing error #[derive(Debug)] pub struct ParseError { pub msg: String, pub location: Location, } impl ParseError { fn from_peg(err: peg::error::ParseError) -> Self { let msg = err.to_string(); Self { msg, location: err.location.offset.into() } } } #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Location { pub(crate) offset: usize, } impl From for Location { fn from(offset: usize) -> Self { Self { offset } } } impl fmt::Display for Location { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.offset) } }