schala/schala-lang/src/parsing/mod.rs

115 lines
3.2 KiB
Rust

#![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 struct Parser {
id_store: IdStore<ASTItem>,
}
impl Parser {
pub(crate) fn new() -> Self {
Self { id_store: IdStore::new() }
}
pub(crate) fn parse(&mut self, input: &str) -> Result<AST, ParseError> {
peg_parser::schala_parser::program(input, self).map_err(ParseError::from_peg)
}
pub(crate) fn parse_comb(&mut self, input: &str) -> Result<AST, ParseError> {
let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra(input, Rc::new(RefCell::new(id_store)));
combinator::program(span).map_err(|err| convert_err(input, err)).map(|(_, output)| output)
}
#[cfg(test)]
fn expression(&mut self, input: &str) -> Result<Expression, ParseError> {
peg_parser::schala_parser::expression(input, self).map_err(ParseError::from_peg)
}
#[cfg(test)]
fn expression_comb(&mut self, input: &str) -> Result<Expression, ParseError> {
let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra(input, Rc::new(RefCell::new(id_store)));
combinator::expression(span).map_err(|err| convert_err(input, err)).map(|(rest, output)| output)
}
#[cfg(test)]
fn block(&mut self, input: &str) -> Result<Block, ParseError> {
peg_parser::schala_parser::block(input, self).map_err(ParseError::from_peg)
}
#[cfg(test)]
fn block_comb(&mut self, input: &str) -> Result<Block, ParseError> {
let id_store: IdStore<ASTItem> = IdStore::new();
let span = Span::new_extra(input, Rc::new(RefCell::new(id_store)));
combinator::block(span).map_err(|err| convert_err(input, err)).map(|(_, output)| output)
}
fn fresh(&mut self) -> Id<ASTItem> {
self.id_store.fresh()
}
}
fn convert_err<'a>(
input: &'a str,
err: nom::Err<nom::error::VerboseError<combinator::Span<'a>>>,
) -> ParseError {
use nom::{error::VerboseError, 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!(),
}
}
/// Represents a parsing error
#[derive(Debug)]
pub struct ParseError {
pub msg: String,
pub location: Location,
}
impl ParseError {
fn from_peg(err: peg::error::ParseError<peg::str::LineCol>) -> 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<usize> 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)
}
}