use core::ops::{Add, AddAssign};
use crate::{
error::{Unclosed, UnexpectedLexeme},
punct::Brace,
utils::{CharLen, Lexeme, PositionedChar, SimpleSpan, human_display::DisplayHuman},
};
use derive_more::{Display, From, IsVariant, TryUnwrap, Unwrap};
pub type InvalidFixedUnicodeHexDigits<Char = char, O = usize> =
crate::error::InvalidHexDigits<Char, 4, O>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MalformedFixedUnicodeEscape<Char = char, O = usize> {
digits: InvalidFixedUnicodeHexDigits<Char, O>,
span: SimpleSpan<O>,
}
impl<Char, O> core::fmt::Display for MalformedFixedUnicodeEscape<Char, O>
where
Char: DisplayHuman,
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"malformed hexadecimal escape sequence with invalid digits at {}, {}",
self.span,
self.digits_ref()
)
}
}
impl<Char, O> core::error::Error for MalformedFixedUnicodeEscape<Char, O>
where
Char: DisplayHuman + core::fmt::Debug,
O: core::fmt::Display + core::fmt::Debug,
{
}
impl<Char, O> MalformedFixedUnicodeEscape<Char, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(digits: InvalidFixedUnicodeHexDigits<Char, O>, span: SimpleSpan<O>) -> Self {
Self { digits, span }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn digits(&self) -> InvalidFixedUnicodeHexDigits<Char, O>
where
Char: Clone,
O: Clone,
{
self.digits.clone()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn digits_ref(&self) -> &InvalidFixedUnicodeHexDigits<Char, O> {
&self.digits
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn digits_mut(&mut self) -> &mut InvalidFixedUnicodeHexDigits<Char, O> {
&mut self.digits
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.span.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.span.as_mut()
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.span.bump(n);
self.digits_mut().bump(n);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InvalidUnicodeScalarKind {
Surrogate,
Overflow,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct InvalidUnicodeScalarValue<O = usize> {
value: u32,
span: SimpleSpan<O>,
kind: InvalidUnicodeScalarKind,
}
impl<O> core::fmt::Display for InvalidUnicodeScalarValue<O>
where
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let cp = self.value;
match self.kind {
InvalidUnicodeScalarKind::Surrogate => write!(
f,
"invalid Unicode scalar value: surrogate code point U+{cp:04X} at {}",
self.span
),
InvalidUnicodeScalarKind::Overflow => write!(
f,
"invalid Unicode scalar value: code point U+{cp:04X} is out of range at {}",
self.span
),
}
}
}
impl<O> core::error::Error for InvalidUnicodeScalarValue<O> where
O: core::fmt::Display + core::fmt::Debug
{
}
impl<O> InvalidUnicodeScalarValue<O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(value: u32, span: SimpleSpan<O>, kind: InvalidUnicodeScalarKind) -> Self {
Self { value, span, kind }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn codepoint(&self) -> u32 {
self.value
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.span.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.span.as_mut()
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.span.bump(n);
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn kind(&self) -> InvalidUnicodeScalarKind {
self.kind
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Display)]
#[display("empty variable-length unicode escape at {_0}")]
pub struct EmptyVariableUnicodeEscape<O = usize>(SimpleSpan<O>);
impl<O> EmptyVariableUnicodeEscape<O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(span: SimpleSpan<O>) -> Self {
Self(span)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.0.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.0.as_mut()
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.0.bump(n);
self
}
}
impl<O> core::error::Error for EmptyVariableUnicodeEscape<O> where
O: core::fmt::Display + core::fmt::Debug
{
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MalformedVariableUnicodeSequence<Char = char, O = usize>(Lexeme<Char, O>);
impl<Char, O> core::fmt::Display for MalformedVariableUnicodeSequence<Char, O>
where
Char: DisplayHuman,
O: core::fmt::Display,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.lexeme_ref() {
Lexeme::Char(positioned_char) => write!(
f,
"invalid variable-length unicode escape character '{}' at position {}",
positioned_char.char_ref().display(),
positioned_char.position_ref()
),
Lexeme::Range(span) => write!(
f,
"malformed variable-length unicode escape sequence at {}",
span
),
}
}
}
impl<Char, O> core::error::Error for MalformedVariableUnicodeSequence<Char, O>
where
Char: DisplayHuman + core::fmt::Debug,
O: core::fmt::Display + core::fmt::Debug,
{
}
impl<Char, O> MalformedVariableUnicodeSequence<Char, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(lexeme: Lexeme<Char, O>) -> Self {
Self(lexeme)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_char(pos: O, ch: Char) -> Self {
Self::from_positioned_char(PositionedChar::with_position(ch, pos))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_positioned_char(ch: PositionedChar<Char, O>) -> Self {
Self(Lexeme::Char(ch))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_range(span: SimpleSpan<O>) -> Self {
Self(Lexeme::Range(span))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn span(&self) -> SimpleSpan<O>
where
Char: CharLen,
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
self.0.span()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn lexeme(&self) -> Lexeme<Char, O>
where
Char: Copy,
O: Copy,
{
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn lexeme_ref(&self) -> &Lexeme<Char, O> {
&self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.0.bump(n);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Display)]
#[display("too many digits ({_1}) in variable-length unicode escape at {_0}")]
pub struct TooManyDigitsInVariableUnicodeEscape<O = usize>(SimpleSpan<O>, usize);
impl<O> TooManyDigitsInVariableUnicodeEscape<O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(span: SimpleSpan<O>, count: usize) -> Self {
Self(span, count)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.0.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.0.as_mut()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn count(&self) -> usize {
self.1
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.0.bump(n);
self
}
}
impl<O> core::error::Error for TooManyDigitsInVariableUnicodeEscape<O> where
O: core::fmt::Display + core::fmt::Debug + 'static
{
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, From, IsVariant, TryUnwrap, Unwrap)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
#[non_exhaustive]
pub enum VariableUnicodeEscapeError<Char = char, O = usize> {
Unclosed(Unclosed<Brace, SimpleSpan<O>>),
Empty(EmptyVariableUnicodeEscape<O>),
TooManyDigits(TooManyDigitsInVariableUnicodeEscape<O>),
Malformed(MalformedVariableUnicodeSequence<Char, O>),
InvalidScalar(InvalidUnicodeScalarValue<O>),
}
impl<Char, O> core::fmt::Display for VariableUnicodeEscapeError<Char, O>
where
Char: DisplayHuman,
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Unclosed(err) => {
write!(
f,
"unclosed variable-length unicode escape at {}",
err.span_ref()
)
}
Self::Empty(err) => err.fmt(f),
Self::TooManyDigits(err) => err.fmt(f),
Self::Malformed(err) => err.fmt(f),
Self::InvalidScalar(err) => err.fmt(f),
}
}
}
impl<Char, O> core::error::Error for VariableUnicodeEscapeError<Char, O>
where
Char: DisplayHuman + core::fmt::Debug + 'static,
O: core::fmt::Display + core::fmt::Debug + 'static,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Unclosed(err) => Some(err),
Self::Empty(err) => Some(err),
Self::TooManyDigits(err) => Some(err),
Self::Malformed(err) => Some(err),
Self::InvalidScalar(err) => Some(err),
}
}
}
impl<Char, O> VariableUnicodeEscapeError<Char, O> {
#[inline]
pub const fn empty(span: SimpleSpan<O>) -> Self {
Self::Empty(EmptyVariableUnicodeEscape::new(span))
}
#[inline]
pub const fn too_many_digits(span: SimpleSpan<O>, count: usize) -> Self {
Self::TooManyDigits(TooManyDigitsInVariableUnicodeEscape::new(span, count))
}
#[inline]
pub const fn unclosed(span: SimpleSpan<O>) -> Self {
Self::Unclosed(Unclosed::new(span, Brace::PHANTOM))
}
#[inline]
pub const fn overflow(span: SimpleSpan<O>, codepoint: u32) -> Self {
Self::InvalidScalar(InvalidUnicodeScalarValue::new(
codepoint,
span,
InvalidUnicodeScalarKind::Overflow,
))
}
#[inline]
pub const fn surrogate(span: SimpleSpan<O>, codepoint: u32) -> Self {
Self::InvalidScalar(InvalidUnicodeScalarValue::new(
codepoint,
span,
InvalidUnicodeScalarKind::Surrogate,
))
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone + Ord + core::hash::Hash,
{
match self {
Self::Unclosed(err) => {
err.bump(n);
}
Self::Empty(err) => {
err.bump(n);
}
Self::TooManyDigits(err) => {
err.bump(n);
}
Self::Malformed(err) => {
err.bump(n);
}
Self::InvalidScalar(err) => {
err.bump(n);
}
}
self
}
pub fn span(&self) -> SimpleSpan<O>
where
Char: CharLen,
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Unclosed(err) => err.span_ref().clone(),
Self::Empty(err) => err.span_ref().cloned(),
Self::TooManyDigits(err) => err.span_ref().cloned(),
Self::Malformed(err) => err.span(),
Self::InvalidScalar(err) => err.span_ref().cloned(),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Display, IsVariant)]
pub enum UnpairedSurrogateHint {
#[display("high surrogate")]
High,
#[display("low surrogate")]
Low,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct IncompleteFixedUnicodeEscape<O = usize>(SimpleSpan<O>);
impl<O> core::fmt::Display for IncompleteFixedUnicodeEscape<O>
where
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"incomplete fixed-width unicode escape sequence at {}, fixed-width unicode escape must contains exactly four hexadecimal digits",
self.0
)
}
}
impl<O> core::error::Error for IncompleteFixedUnicodeEscape<O> where
O: core::fmt::Display + core::fmt::Debug
{
}
impl<O> IncompleteFixedUnicodeEscape<O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(span: SimpleSpan<O>) -> Self {
Self(span)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> SimpleSpan<O>
where
O: Copy,
{
self.0
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> SimpleSpan<&O> {
self.0.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> SimpleSpan<&mut O> {
self.0.as_mut()
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
self.0.bump(n);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, From, IsVariant, TryUnwrap, Unwrap)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
#[non_exhaustive]
pub enum FixedUnicodeEscapeError<Char = char, O = usize> {
Incomplete(IncompleteFixedUnicodeEscape<O>),
Malformed(MalformedFixedUnicodeEscape<Char, O>),
UnpairedSurrogate(UnexpectedLexeme<Char, UnpairedSurrogateHint, O>),
}
impl<Char, O> core::fmt::Display for FixedUnicodeEscapeError<Char, O>
where
Char: DisplayHuman + CharLen,
O: core::fmt::Display + Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Incomplete(err) => err.fmt(f),
Self::Malformed(err) => err.fmt(f),
Self::UnpairedSurrogate(err) => match err.hint() {
UnpairedSurrogateHint::High => write!(
f,
"unpaired high surrogate in fixed-width unicode escape at {}",
err.span(),
),
UnpairedSurrogateHint::Low => write!(
f,
"unpaired low surrogate in fixed-width unicode escape at {}",
err.span()
),
},
}
}
}
impl<Char, O> core::error::Error for FixedUnicodeEscapeError<Char, O>
where
Char: DisplayHuman + CharLen + core::fmt::Debug + 'static,
O: core::fmt::Display + core::fmt::Debug + 'static + Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Incomplete(_) => None,
Self::Malformed(err) => Some(err),
Self::UnpairedSurrogate(err) => Some(err),
}
}
}
impl<Char, O> FixedUnicodeEscapeError<Char, O> {
#[inline]
pub const fn unpaired_high_surrogate(lexeme: Lexeme<Char, O>) -> Self {
Self::UnpairedSurrogate(UnexpectedLexeme::new(lexeme, UnpairedSurrogateHint::High))
}
#[inline]
pub const fn unpaired_low_surrogate(lexeme: Lexeme<Char, O>) -> Self {
Self::UnpairedSurrogate(UnexpectedLexeme::new(lexeme, UnpairedSurrogateHint::Low))
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
match self {
Self::Incomplete(lexeme) => {
lexeme.bump(n);
}
Self::Malformed(seq) => {
seq.bump(n);
}
Self::UnpairedSurrogate(lexeme) => {
lexeme.bump(n);
}
}
self
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn span(&self) -> SimpleSpan<O>
where
Char: CharLen,
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Incomplete(lexeme) => lexeme.span_ref().cloned(),
Self::Malformed(seq) => seq.span_ref().cloned(),
Self::UnpairedSurrogate(lexeme) => lexeme.span(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, From, IsVariant, TryUnwrap, Unwrap)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
#[non_exhaustive]
pub enum UnicodeEscapeError<Char = char, O = usize> {
Fixed(FixedUnicodeEscapeError<Char, O>),
Variable(VariableUnicodeEscapeError<Char, O>),
}
impl<Char, O> core::fmt::Display for UnicodeEscapeError<Char, O>
where
Char: DisplayHuman + CharLen,
O: core::fmt::Display + Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Fixed(err) => err.fmt(f),
Self::Variable(err) => err.fmt(f),
}
}
}
impl<Char, O> core::error::Error for UnicodeEscapeError<Char, O>
where
Char: DisplayHuman + CharLen + core::fmt::Debug + 'static,
O: core::fmt::Display + core::fmt::Debug + Clone + Ord + 'static,
for<'a> &'a O: Add<usize, Output = O>,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Fixed(err) => Some(err),
Self::Variable(err) => Some(err),
}
}
}
impl<Char, O> UnicodeEscapeError<Char, O> {
#[inline]
pub const fn unpaired_high_surrogate(lexeme: Lexeme<Char, O>) -> Self {
Self::Fixed(FixedUnicodeEscapeError::unpaired_high_surrogate(lexeme))
}
#[inline]
pub const fn unpaired_low_surrogate(lexeme: Lexeme<Char, O>) -> Self {
Self::Fixed(FixedUnicodeEscapeError::unpaired_low_surrogate(lexeme))
}
#[inline]
pub const fn incomplete_fixed_unicode_escape(span: SimpleSpan<O>) -> Self {
Self::Fixed(FixedUnicodeEscapeError::Incomplete(
IncompleteFixedUnicodeEscape::new(span),
))
}
#[inline]
pub const fn malformed_fixed_unicode_escape(
digits: InvalidFixedUnicodeHexDigits<Char, O>,
span: SimpleSpan<O>,
) -> Self {
Self::Fixed(FixedUnicodeEscapeError::Malformed(
MalformedFixedUnicodeEscape::new(digits, span),
))
}
#[inline]
pub const fn empty_variable_unicode_escape(span: SimpleSpan<O>) -> Self {
Self::Variable(VariableUnicodeEscapeError::empty(span))
}
#[inline]
pub const fn too_many_digits_in_variable_unicode_escape(
span: SimpleSpan<O>,
count: usize,
) -> Self {
Self::Variable(VariableUnicodeEscapeError::too_many_digits(span, count))
}
#[inline]
pub const fn unclosed_variable_unicode_escape(span: SimpleSpan<O>) -> Self {
Self::Variable(VariableUnicodeEscapeError::unclosed(span))
}
#[inline]
pub const fn surrogate_variable_unicode_escape(span: SimpleSpan<O>, codepoint: u32) -> Self {
Self::Variable(VariableUnicodeEscapeError::surrogate(span, codepoint))
}
#[inline]
pub const fn overflow_variable_unicode_escape(span: SimpleSpan<O>, codepoint: u32) -> Self {
Self::Variable(VariableUnicodeEscapeError::overflow(span, codepoint))
}
#[inline]
pub const fn invalid_variable_unicode_escape_char(pos: O, ch: Char) -> Self {
Self::Variable(VariableUnicodeEscapeError::Malformed(
MalformedVariableUnicodeSequence::from_char(pos, ch),
))
}
#[inline]
pub const fn invalid_variable_unicode_escape_sequence(span: SimpleSpan<O>) -> Self {
Self::Variable(VariableUnicodeEscapeError::Malformed(
MalformedVariableUnicodeSequence::from_range(span),
))
}
#[inline]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone + Ord + core::hash::Hash,
{
match self {
Self::Fixed(err) => {
err.bump(n);
}
Self::Variable(err) => {
err.bump(n);
}
}
self
}
#[inline]
pub fn span(&self) -> SimpleSpan<O>
where
Char: CharLen,
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Fixed(err) => err.span(),
Self::Variable(err) => err.span(),
}
}
}