use std::sync::Arc;
use crate::scanner;
use crate::token::CarriageReturn;
use crate::token::Ident;
use crate::token::LitChar;
use crate::token::LitFloat;
use crate::token::LitInt;
use crate::token::LitStrDoubleQuote;
use crate::token::LitStrSingleQuote;
use crate::token::NewLine;
use crate::token::PunctKind;
use crate::token::SingleCharPunct;
use crate::token::Space2;
use crate::token::Space4;
use crate::token::Spacing;
use crate::token::Tab;
use crate::token::Token;
use crate::token::WhiteSpace;
use crate::Entry;
use crate::Span;
use crate::TokenStream;
pub trait ToTokens {
fn to_tokens(&self, tokens: &mut TokenStream);
fn to_token_stream(&self) -> TokenStream {
let mut tokens = TokenStream::new(vec![], None);
self.to_tokens(&mut tokens);
tokens
}
fn into_token_stream(self) -> TokenStream
where
Self: Sized,
{
self.to_token_stream()
}
}
impl<'a, T: ?Sized + ToTokens> ToTokens for &'a T {
fn to_tokens(&self, tokens: &mut TokenStream) {
T::to_tokens(self, tokens);
}
fn to_token_stream(&self) -> TokenStream {
T::to_token_stream(self)
}
}
impl<'a, T: ?Sized + ToTokens> ToTokens for &'a mut T {
fn to_tokens(&self, tokens: &mut TokenStream) {
T::to_tokens(self, tokens);
}
fn to_token_stream(&self) -> TokenStream {
T::to_token_stream(self)
}
}
impl<T: ToTokens> ToTokens for Option<T> {
fn to_tokens(&self, tokens: &mut TokenStream) {
if let Some(value) = self {
value.to_tokens(tokens);
}
}
fn to_token_stream(&self) -> TokenStream {
self.as_ref()
.map_or_else(|| TokenStream::new(vec![], None), ToTokens::to_token_stream)
}
fn into_token_stream(self) -> TokenStream {
self.map_or_else(
|| TokenStream::new(vec![], None),
ToTokens::into_token_stream,
)
}
}
impl ToTokens for TokenStream {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.tokens.append(&mut self.tokens.clone());
}
fn to_token_stream(&self) -> TokenStream {
self.clone()
}
fn into_token_stream(self) -> TokenStream
where
Self: Sized,
{
self
}
}
macro_rules! impl_nums {
[$($ty:ty),* $(,)?] => {
$(
impl ToTokens for $ty {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.tokens.push(Entry::Ident(Ident::new(self.to_string(), Span::empty())));
}
}
)*
};
}
impl_nums![u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64];
impl ToTokens for str {
fn to_tokens(&self, tokens: &mut TokenStream) {
LitStrDoubleQuote::new(self.to_string(), Span::empty()).to_tokens(tokens);
}
}
impl ToTokens for String {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.as_str().to_tokens(tokens);
}
}
fn str_to_tokens(string: &str, span: &Span, delimiter: PunctKind, tokens: &mut TokenStream) {
let start_spacing = string.chars().next().map_or(Spacing::Joint, |ch| {
if PunctKind::try_from(ch).is_ok() {
Spacing::Joint
} else {
Spacing::Alone
}
});
let start_span = Span::new(span.start, span.start + 1, Arc::clone(&span.source));
let start = Entry::Punct(SingleCharPunct::new(delimiter, start_spacing, start_span));
tokens.push(start);
let (
TokenStream {
tokens: mut new_tokens,
source: _,
},
_,
) = scanner::scan(Arc::clone(&span.source), span.start + 1, Some(span.end - 1));
tokens.tokens.append(&mut new_tokens);
let end_span = Span::new(span.end - 1, span.end, Arc::clone(&span.source));
let end = Entry::Punct(SingleCharPunct::new(delimiter, Spacing::Alone, end_span));
tokens.push(end);
}
impl ToTokens for LitStrDoubleQuote {
fn to_tokens(&self, tokens: &mut TokenStream) {
str_to_tokens(self.string(), self.span(), PunctKind::DoubleQuote, tokens);
}
}
impl ToTokens for LitStrSingleQuote {
fn to_tokens(&self, tokens: &mut TokenStream) {
str_to_tokens(self.string(), self.span(), PunctKind::SingleQuote, tokens);
}
}
impl ToTokens for LitChar {
fn to_tokens(&self, tokens: &mut TokenStream) {
let start_spacing = if PunctKind::try_from(self.ch()).is_ok() {
Spacing::Joint
} else {
Spacing::Alone
};
let start_span = Span::new(
self.span().start,
self.span().start + 1,
Arc::clone(&self.span().source),
);
let start = Entry::Punct(SingleCharPunct::new(
PunctKind::SingleQuote,
start_spacing,
start_span,
));
tokens.push(start);
tokens.push(Entry::Ident(Ident::new(
self.ch().to_string(),
Span::empty(),
)));
let end_span = Span::new(
self.span().end - 1,
self.span().end,
Arc::clone(&self.span().source),
);
let end = Entry::Punct(SingleCharPunct::new(
PunctKind::SingleQuote,
Spacing::Alone,
end_span,
));
tokens.push(end);
}
}
impl ToTokens for Ident {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::Ident(self.clone()));
}
fn into_token_stream(self) -> TokenStream {
let source = Arc::clone(&self.span.source);
TokenStream::new(vec![Entry::Ident(self)], Some(source))
}
}
impl ToTokens for LitInt {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::Ident(Ident::new(
self.value().to_string(),
self.span().clone(),
)));
}
}
impl ToTokens for LitFloat {
#[allow(clippy::cast_sign_loss)] fn to_tokens(&self, tokens: &mut TokenStream) {
debug_assert!(self.value() >= 0.0, "literals must not be signed");
let start = (self.value() - self.value().fract()).floor() as u64;
let num_start_digits = start.checked_ilog10().unwrap_or(0) + 1;
let mut fract = self.value().fract();
while fract.fract() != 0.0 {
fract *= 10.0;
}
let end = fract as u64;
let num_end_digits = end.checked_ilog10().unwrap_or(0) + 1;
tokens.push(Entry::Ident(Ident::new(
start.to_string(),
Span::new(
self.span().start,
self.span().start + num_start_digits as usize,
Arc::clone(&self.span().source),
),
)));
tokens.push(Entry::Punct(SingleCharPunct::new(
PunctKind::Dot,
Spacing::Alone,
Span::new(
num_start_digits as usize,
num_start_digits as usize + 1,
Arc::clone(&self.span().source),
),
)));
tokens.push(Entry::Ident(Ident::new(
end.to_string(),
Span::new(
self.span().end - num_end_digits as usize,
self.span().end,
Arc::clone(&self.span().source),
),
)));
}
}
impl ToTokens for WhiteSpace {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::WhiteSpace(self.clone()));
}
}
impl ToTokens for Space2 {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::WhiteSpace(WhiteSpace::Space2(self.clone())));
}
}
impl ToTokens for Space4 {
fn to_tokens(&self, tokens: &mut TokenStream) {
let start_span = Span::new(
self.span.start,
self.span.start + 2,
Arc::clone(&self.span.source),
);
tokens.push(Entry::WhiteSpace(WhiteSpace::Space2(Space2 {
span: start_span,
})));
let end_span = Span::new(
self.span.end - 2,
self.span.end,
Arc::clone(&self.span.source),
);
tokens.push(Entry::WhiteSpace(WhiteSpace::Space2(Space2 {
span: end_span,
})));
}
}
impl ToTokens for Tab {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::WhiteSpace(WhiteSpace::Tab(self.clone())));
}
}
impl ToTokens for NewLine {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::WhiteSpace(WhiteSpace::NewLine(self.clone())));
}
}
impl ToTokens for CarriageReturn {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.push(Entry::WhiteSpace(WhiteSpace::CarriageReturn(self.clone())));
}
}