Move parsing of literals under new 'literal' parser module group

Also moved the logic for 'int' and 'string' there though it is trivial. Yet, for bytearray, it tidies things nicely by removing them from the 'utils' module.
This commit is contained in:
KtorZ 2023-07-05 14:36:23 +02:00
parent e15cdaf248
commit 66296df9c3
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
9 changed files with 123 additions and 96 deletions

View File

@ -4,6 +4,7 @@ pub mod error;
pub mod expr;
pub mod extra;
pub mod lexer;
pub mod literal;
pub mod pattern;
pub mod token;
mod utils;

View File

@ -2,7 +2,9 @@ use chumsky::prelude::*;
use crate::{
ast,
parser::{annotation, error::ParseError, expr::bytearray::bytearray, token::Token, utils},
parser::{
annotation, error::ParseError, literal::bytearray::parser as bytearray, token::Token, utils,
},
};
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
@ -48,7 +50,7 @@ pub fn value() -> impl Parser<Token, ast::Constant, Error = ParseError> {
});
let constant_bytearray_parser =
bytearray().map_with_span(|(preferred_format, bytes), span| ast::Constant::ByteArray {
bytearray(|bytes, preferred_format, span| ast::Constant::ByteArray {
location: span,
bytes,
preferred_format,

View File

@ -1,98 +1,17 @@
use chumsky::prelude::*;
use crate::{
ast,
expr::UntypedExpr,
parser::{
error::{self, ParseError},
token::{Base, Token},
},
use crate::parser::{
error::ParseError, expr::UntypedExpr, literal::bytearray::parser as bytearray, token::Token,
};
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
bytearray().map_with_span(|(preferred_format, bytes), span| UntypedExpr::ByteArray {
location: span,
bytearray(|bytes, preferred_format, location| UntypedExpr::ByteArray {
location,
bytes,
preferred_format,
})
}
pub fn bytearray(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
choice((array_of_bytes(), hex_string(), utf8_string()))
}
pub fn array_of_bytes(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
just(Token::Hash)
.ignore_then(
select! {Token::Int {value, base, ..} => (value, base)}
.validate(|(value, base), span, emit| {
let byte: u8 = match value.parse() {
Ok(b) => b,
Err(_) => {
emit(ParseError::expected_input_found(
span,
None,
Some(error::Pattern::Byte),
));
0
}
};
(byte, base)
})
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
)
.validate(|bytes, span, emit| {
let base = bytes.iter().fold(Ok(None), |acc, (_, base)| match acc {
Ok(None) => Ok(Some(base)),
Ok(Some(previous_base)) if previous_base == base => Ok(Some(base)),
_ => Err(()),
});
let base = match base {
Err(()) => {
emit(ParseError::hybrid_notation_in_bytearray(span));
Base::Decimal {
numeric_underscore: false,
}
}
Ok(None) => Base::Decimal {
numeric_underscore: false,
},
Ok(Some(base)) => *base,
};
(bytes.into_iter().map(|(b, _)| b).collect::<Vec<u8>>(), base)
})
.map(|(bytes, base)| (ast::ByteArrayFormatPreference::ArrayOfBytes(base), bytes))
}
pub fn hex_string(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
just(Token::Hash)
.ignore_then(
select! {Token::ByteString {value} => value}.validate(|value, span, emit| {
match hex::decode(value) {
Ok(bytes) => bytes,
Err(_) => {
emit(ParseError::malformed_base16_string_literal(span));
vec![]
}
}
}),
)
.map(|token| (ast::ByteArrayFormatPreference::HexadecimalString, token))
}
pub fn utf8_string(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
select! {Token::ByteString {value} => value.into_bytes() }
.map(|token| (ast::ByteArrayFormatPreference::Utf8String, token))
}
#[cfg(test)]
mod tests {
use crate::assert_expr;

View File

@ -2,16 +2,14 @@ use chumsky::prelude::*;
use crate::{
expr::UntypedExpr,
parser::{error::ParseError, token::Token},
parser::{error::ParseError, literal::int::parser as int, token::Token},
};
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
select! { Token::Int {value, base} => (value, base)}.map_with_span(|(value, base), span| {
UntypedExpr::Int {
int().map_with_span(|(value, base), span| UntypedExpr::Int {
location: span,
value,
base,
}
})
}

View File

@ -3,11 +3,11 @@ use chumsky::prelude::*;
use crate::{
ast,
expr::UntypedExpr,
parser::{error::ParseError, token::Token},
parser::{error::ParseError, literal::string::parser as string, token::Token},
};
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
select! {Token::String {value} => value}.map_with_span(|value, span| UntypedExpr::String {
string().map_with_span(|value, span| UntypedExpr::String {
location: span,
value,
})

View File

@ -0,0 +1,87 @@
use chumsky::prelude::*;
use crate::{
ast,
parser::{
error::{self, ParseError},
token::{Base, Token},
},
};
pub fn parser<A>(
into: impl Fn(Vec<u8>, ast::ByteArrayFormatPreference, ast::Span) -> A,
) -> impl Parser<Token, A, Error = ParseError> {
choice((array_of_bytes(), hex_string(), utf8_string()))
.map_with_span(move |(preferred_format, bytes), span| into(bytes, preferred_format, span))
}
pub fn array_of_bytes(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
just(Token::Hash)
.ignore_then(
select! {Token::Int {value, base, ..} => (value, base)}
.validate(|(value, base), span, emit| {
let byte: u8 = match value.parse() {
Ok(b) => b,
Err(_) => {
emit(ParseError::expected_input_found(
span,
None,
Some(error::Pattern::Byte),
));
0
}
};
(byte, base)
})
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftSquare), just(Token::RightSquare)),
)
.validate(|bytes, span, emit| {
let base = bytes.iter().fold(Ok(None), |acc, (_, base)| match acc {
Ok(None) => Ok(Some(base)),
Ok(Some(previous_base)) if previous_base == base => Ok(Some(base)),
_ => Err(()),
});
let base = match base {
Err(()) => {
emit(ParseError::hybrid_notation_in_bytearray(span));
Base::Decimal {
numeric_underscore: false,
}
}
Ok(None) => Base::Decimal {
numeric_underscore: false,
},
Ok(Some(base)) => *base,
};
(bytes.into_iter().map(|(b, _)| b).collect::<Vec<u8>>(), base)
})
.map(|(bytes, base)| (ast::ByteArrayFormatPreference::ArrayOfBytes(base), bytes))
}
pub fn hex_string(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
just(Token::Hash)
.ignore_then(
select! {Token::ByteString {value} => value}.validate(|value, span, emit| {
match hex::decode(value) {
Ok(bytes) => bytes,
Err(_) => {
emit(ParseError::malformed_base16_string_literal(span));
vec![]
}
}
}),
)
.map(|token| (ast::ByteArrayFormatPreference::HexadecimalString, token))
}
pub fn utf8_string(
) -> impl Parser<Token, (ast::ByteArrayFormatPreference, Vec<u8>), Error = ParseError> {
select! {Token::ByteString {value} => value.into_bytes() }
.map(|token| (ast::ByteArrayFormatPreference::Utf8String, token))
}

View File

@ -0,0 +1,10 @@
use chumsky::prelude::*;
use crate::parser::{
error::ParseError,
token::{Base, Token},
};
pub fn parser() -> impl Parser<Token, (String, Base), Error = ParseError> {
select! { Token::Int {value, base} => (value, base)}
}

View File

@ -0,0 +1,3 @@
pub(crate) mod bytearray;
pub(crate) mod int;
pub(crate) mod string;

View File

@ -0,0 +1,7 @@
use chumsky::prelude::*;
use crate::parser::{error::ParseError, token::Token};
pub fn parser() -> impl Parser<Token, String, Error = ParseError> {
select! {Token::String {value} => value}
}