use nom::{
character::complete::{multispace0, multispace1},
error::ParseError,
multi::many0,
sequence::delimited,
IResult, Parser,
};
use statement::parse_statement;
use thiserror::Error;
pub(crate) mod expression;
pub(crate) mod statement;
pub use expression::{Associativity, BinaryOperator, Expression, StringLiteral, UnaryOperator};
pub use statement::Statement;
#[derive(Error, Debug, PartialEq)]
pub enum SyntaxErrorKind {
#[error("Empty input")]
EmptyInput,
#[error("Trailing characters")]
TrailingCharacters,
#[error("Numeric literals cannot have consecutive underscores")]
ConsecutiveUnderscoreInNumericLiteral,
#[error("Numeric literals cannot start with an underscore")]
NumericLiteralStartsWithUnderscore,
#[error("Numeric literals cannot end with an underscore")]
NumericLiteralEndsWithUnderscore,
#[error("Empty bigint literal")]
EmptyBigIntLiteral,
#[error("Invalid hexadecimal digit")]
InvalidHexDigit,
#[error("Missing opening brace in unicode code point escape sequence")]
MissingUnicodeCodePointOpeningBrace,
#[error("Missing closing brace in unicode code point escape sequence")]
MissingUnicodeCodePointClosingBrace,
#[error("Invalid unicode code point: {0}")]
InvalidUnicodeCodePoint(u32),
#[error("Nom error: {0:?}")]
NomError(nom::error::ErrorKind),
}
#[derive(Debug, PartialEq)]
pub struct SyntaxError<'a> {
pub input: &'a str,
pub error: SyntaxErrorKind,
}
impl<'a> nom::error::ParseError<&'a str> for SyntaxError<'a> {
fn from_error_kind(input: &'a str, kind: nom::error::ErrorKind) -> Self {
SyntaxError {
input,
error: match kind {
nom::error::ErrorKind::Eof => SyntaxErrorKind::EmptyInput,
_ => SyntaxErrorKind::NomError(kind),
},
}
}
fn append(_: &'a str, _: nom::error::ErrorKind, other: Self) -> Self {
other
}
}
pub type ParseResult<'a, T> = IResult<&'a str, T, SyntaxError<'a>>;
pub fn parse(input: &str) -> ParseResult<Vec<Statement>> {
if input.is_empty() {
return Err(nom::Err::Failure(SyntaxError {
input,
error: SyntaxErrorKind::EmptyInput,
}));
}
let (remaining, parsed) = many0(ws0(parse_statement)).parse(input)?;
if remaining.is_empty() {
return Ok((remaining, parsed));
}
Err(nom::Err::Failure(SyntaxError {
input,
error: SyntaxErrorKind::TrailingCharacters,
}))
}
fn ws0<'a, O, E: ParseError<&'a str>, F>(inner: F) -> impl Parser<&'a str, Output = O, Error = E>
where
F: Parser<&'a str, Output = O, Error = E>,
{
delimited(multispace0, inner, multispace0)
}
fn ws1<'a, O, E: ParseError<&'a str>, F>(inner: F) -> impl Parser<&'a str, Output = O, Error = E>
where
F: Parser<&'a str, Output = O, Error = E>,
{
delimited(multispace1, inner, multispace1)
}