#![allow(clippy::upper_case_acronyms)] pub mod combinator; mod peg_parser; mod test; use std::fmt; #[cfg(test)] use crate::ast::{Block, Expression}; use crate::{ ast::{ASTItem, AST}, identifier::{Id, IdStore}, }; pub struct Parser { id_store: IdStore, } impl Parser { pub(crate) fn new() -> Self { Self { id_store: IdStore::new() } } pub(crate) fn parse(&mut self, input: &str) -> Result { peg_parser::schala_parser::program(input, self).map_err(ParseError::from_peg) } #[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 { use std::{cell::RefCell, rc::Rc}; use combinator::Span; use nom::{error::VerboseError, Err}; let id_store: IdStore = IdStore::new(); let span = Span::new_extra(input, Rc::new(RefCell::new(id_store))); combinator::expression(span) .map_err(|err| match err { Err::Error(err) | Err::Failure(err) => { let err = VerboseError { errors: err.errors.into_iter().map(|(sp, kind)| (*sp.fragment(), kind)).collect(), }; let msg = nom::error::convert_error(input, err); ParseError { msg, location: (0).into() } } _ => panic!(), }) .map(|(_, output)| output) } #[cfg(test)] fn block(&mut self, input: &str) -> Result { peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg) } fn fresh(&mut self) -> Id { self.id_store.fresh() } } /// 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) } }