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:
parent
e15cdaf248
commit
66296df9c3
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
location: span,
|
||||
value,
|
||||
base,
|
||||
}
|
||||
int().map_with_span(|(value, base), span| UntypedExpr::Int {
|
||||
location: span,
|
||||
value,
|
||||
base,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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)}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub(crate) mod bytearray;
|
||||
pub(crate) mod int;
|
||||
pub(crate) mod string;
|
|
@ -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}
|
||||
}
|
Loading…
Reference in New Issue