use core::marker::PhantomData;
use crate::{
error::ErrorNode,
utils::{AsSpan, IntoComponents},
};
macro_rules! define_literal {
(
$(#[$meta:meta])*
$name:ident,
$doc:expr,
$example_str:expr,
$example_desc:expr
) => {
paste::paste! {
$(#[$meta])*
#[doc = $doc]
#[doc = "use tokit::types::" $name ";"]
#[doc = "let lit = " $name "::<&str, MyLang>::new("]
#[doc = " Span::new(0, 4),"]
#[doc = " " $example_str ]
#[doc = "assert_eq!(lit.source_ref(), &" $example_str ");"]
#[doc = "use tokit::types::" $name ";"]
#[doc = "// " $example_desc]
#[doc = "let bad_lit = " $name "::<String, YulLang>::error(span);"]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name<D, S = $crate::__private::utils::SimpleSpan, Lang = ()> {
span: S,
data: D,
_lang: PhantomData<Lang>,
}
}
impl<D, S, Lang> AsSpan<S> for $name<D, S, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
fn as_span(&self) -> &S {
self.span_ref()
}
}
impl<D, S, Lang> IntoComponents for $name<D, S, Lang> {
type Components = (S, D);
#[cfg_attr(not(tarpaulin), inline(always))]
fn into_components(self) -> Self::Components {
(self.span, self.data)
}
}
impl<D, S, Lang> $name<D, S, Lang> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn new(span: S, data: D) -> Self {
Self {
span,
data,
_lang: PhantomData,
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span(&self) -> S where S: ::core::marker::Copy {
self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_ref(&self) -> &S {
&self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn span_mut(&mut self) -> &mut S {
&mut self.span
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data_mut(&mut self) -> &mut D {
&mut self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data_ref(&self) -> &D {
&self.data
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn data(&self) -> D
where
D: Copy,
{
self.data
}
}
impl<D, S, Lang> ErrorNode<S> for $name<D, S, Lang>
where
D: ErrorNode<S>,
S: Clone,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn error(span: S) -> Self {
Self::new(span.clone(), D::error(span))
}
#[cfg_attr(not(tarpaulin), inline(always))]
fn missing(span: S) -> Self {
Self::new(span.clone(), D::missing(span))
}
}
};
}
define_literal!(
Lit,
"A generic literal (any literal type).",
"\"value\"",
"Malformed literal"
);
define_literal!(
LitDecimal,
"A decimal integer literal (e.g., `42`, `1_000`).",
"\"42\"",
"Malformed decimal literal like \"12abc\""
);
define_literal!(
LitHex,
"A hexadecimal integer literal (e.g., `0xFF`, `0x1A2B`).",
"\"0xFF\"",
"Malformed hex literal like \"0xGG\""
);
define_literal!(
LitOctal,
"An octal integer literal (e.g., `0o77`, `0o644`).",
"\"0o77\"",
"Malformed octal literal like \"0o89\""
);
define_literal!(
LitBinary,
"A binary integer literal (e.g., `0b1010`, `0b1111_0000`).",
"\"0b1010\"",
"Malformed binary literal like \"0b123\""
);
define_literal!(
LitFloat,
"A floating-point literal (e.g., `3.14`, `1.0e-5`).",
"\"3.14\"",
"Malformed float literal like \"3.14.15\""
);
define_literal!(
LitHexFloat,
"A hexadecimal floating-point literal (e.g., `0x1.8p3`).",
"\"0x1.8p3\"",
"Malformed hex float like \"0x1.Gp3\""
);
define_literal!(
LitString,
"A single-line string literal (e.g., `\"hello\"`, `\"world\\n\"`).",
"\"\\\"hello\\\"\"",
"Malformed string like unterminated \"hello"
);
define_literal!(
LitMultilineString,
"A multi-line string literal (e.g., `\"\"\"...\"\"\"`).",
"\"\\\"\\\"\\\"multi\\nline\\\"\\\"\\\"\"",
"Malformed multiline string"
);
define_literal!(
LitRawString,
"A raw string literal without escape processing (e.g., `r\"C:\\path\"`).",
"\"r\\\"C:\\\\path\\\"\"",
"Malformed raw string"
);
define_literal!(
LitChar,
"A character literal (e.g., `'a'`, `'\\n'`, `'\\u{1F600}'`).",
"\"'a'\"",
"Malformed char like unclosed 'a"
);
define_literal!(
LitByte,
"A byte literal (e.g., `b'a'`, `b'\\x7F'`).",
"\"b'a'\"",
"Malformed byte literal"
);
define_literal!(
LitByteString,
"A byte string literal (e.g., `b\"bytes\"`, `b\"\\x48\\x65\\x6C\\x6C\\x6F\"`).",
"\"b\\\"bytes\\\"\"",
"Malformed byte string"
);
define_literal!(
LitBool,
"A boolean literal (`true` or `false`).",
"\"true\"",
"Malformed boolean like \"tru\" or \"fals\""
);
define_literal!(
LitNull,
"A null/nil literal (e.g., `null`, `nil`, `None`).",
"\"null\"",
"Malformed null literal"
);