blanket_script/parser/
mod.rs1use nom::{
2 character::complete::{multispace0, multispace1},
3 error::ParseError,
4 multi::many0,
5 sequence::delimited,
6 IResult, Parser,
7};
8use statement::parse_statement;
9use thiserror::Error;
10
11pub(crate) mod expression;
12pub(crate) mod statement;
13
14pub use expression::{Associativity, BinaryOperator, Expression, StringLiteral, UnaryOperator};
15pub use statement::Statement;
16
17#[derive(Error, Debug, PartialEq)]
18pub enum SyntaxErrorKind {
19 #[error("Empty input")]
20 EmptyInput,
21 #[error("Trailing characters")]
22 TrailingCharacters,
23 #[error("Numeric literals cannot have consecutive underscores")]
24 ConsecutiveUnderscoreInNumericLiteral,
25 #[error("Numeric literals cannot start with an underscore")]
26 NumericLiteralStartsWithUnderscore,
27 #[error("Numeric literals cannot end with an underscore")]
28 NumericLiteralEndsWithUnderscore,
29 #[error("Empty bigint literal")]
30 EmptyBigIntLiteral,
31 #[error("Invalid hexadecimal digit")]
32 InvalidHexDigit,
33 #[error("Missing opening brace in unicode code point escape sequence")]
34 MissingUnicodeCodePointOpeningBrace,
35 #[error("Missing closing brace in unicode code point escape sequence")]
36 MissingUnicodeCodePointClosingBrace,
37 #[error("Invalid unicode code point: {0}")]
38 InvalidUnicodeCodePoint(u32),
39 #[error("Nom error: {0:?}")]
40 NomError(nom::error::ErrorKind),
41}
42
43#[derive(Debug, PartialEq)]
44pub struct SyntaxError<'a> {
45 pub input: &'a str,
46 pub error: SyntaxErrorKind,
47}
48
49impl<'a> nom::error::ParseError<&'a str> for SyntaxError<'a> {
50 fn from_error_kind(input: &'a str, kind: nom::error::ErrorKind) -> Self {
51 SyntaxError {
52 input,
53 error: match kind {
54 nom::error::ErrorKind::Eof => SyntaxErrorKind::EmptyInput,
55 _ => SyntaxErrorKind::NomError(kind),
56 },
57 }
58 }
59
60 fn append(_: &'a str, _: nom::error::ErrorKind, other: Self) -> Self {
61 other
62 }
63}
64
65pub type ParseResult<'a, T> = IResult<&'a str, T, SyntaxError<'a>>;
66
67pub fn parse(input: &str) -> ParseResult<Vec<Statement>> {
68 if input.is_empty() {
69 return Err(nom::Err::Failure(SyntaxError {
70 input,
71 error: SyntaxErrorKind::EmptyInput,
72 }));
73 }
74 let (remaining, parsed) = many0(ws0(parse_statement)).parse(input)?;
75 if remaining.is_empty() {
76 return Ok((remaining, parsed));
77 }
78 Err(nom::Err::Failure(SyntaxError {
79 input,
80 error: SyntaxErrorKind::TrailingCharacters,
81 }))
82}
83
84fn ws0<'a, O, E: ParseError<&'a str>, F>(inner: F) -> impl Parser<&'a str, Output = O, Error = E>
86where
87 F: Parser<&'a str, Output = O, Error = E>,
88{
89 delimited(multispace0, inner, multispace0)
90}
91
92fn ws1<'a, O, E: ParseError<&'a str>, F>(inner: F) -> impl Parser<&'a str, Output = O, Error = E>
94where
95 F: Parser<&'a str, Output = O, Error = E>,
96{
97 delimited(multispace1, inner, multispace1)
98}