use core::ascii;
use core::fmt;
use core::ops::Neg;
use crate::ast::prelude::*;
use crate::ast::{Kind, Span, Spanned};
use crate::compile;
use crate::macros::{MacroContext, SyntheticId, ToTokens, TokenStream};
use crate::parse::{Expectation, IntoExpectation, Parse, Parser, Peek};
use crate::SourceId;
#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub struct Token {
pub span: Span,
pub kind: Kind,
}
impl Token {
pub(crate) fn token_fmt(&self, cx: &MacroContext, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
Kind::Eof | Kind::Error => {
return Err(fmt::Error);
}
Kind::Ident(s) => {
let literal = cx.literal_source(*s, self.span).ok_or(fmt::Error)?;
write!(f, "{}", literal)?;
}
Kind::Label(s) => {
let literal = cx.literal_source(*s, self.span).ok_or(fmt::Error)?;
write!(f, "'{}", literal)?;
}
Kind::Byte(s) => match s {
CopySource::Text(source_id) => {
let s = cx
.idx
.q
.sources
.source(*source_id, self.span)
.ok_or(fmt::Error)?;
write!(f, "{}", s)?;
}
CopySource::Inline(b) => {
write!(f, "{:?}", b)?;
}
},
Kind::ByteStr(s) => match s {
StrSource::Text(text) => {
let span = if text.wrapped {
self.span.narrow(1u32)
} else {
self.span
};
let s = cx
.idx
.q
.sources
.source(text.source_id, span)
.ok_or(fmt::Error)?;
write!(f, "b\"{}\"", s)?;
}
StrSource::Synthetic(id) => {
let b = cx.idx.q.storage.get_byte_string(*id).ok_or(fmt::Error)?;
write!(f, "{}", FormatBytes(b))?;
}
},
Kind::Str(s) => match s {
StrSource::Text(text) => {
let span = if text.wrapped {
self.span.narrow(1u32)
} else {
self.span
};
let s = cx
.idx
.q
.sources
.source(text.source_id, span)
.ok_or(fmt::Error)?;
write!(f, "\"{}\"", s)?;
}
StrSource::Synthetic(id) => {
let s = cx.idx.q.storage.get_string(*id).ok_or(fmt::Error)?;
write!(f, "{:?}", s)?;
}
},
Kind::Char(s) => match s {
CopySource::Text(source_id) => {
let s = cx
.idx
.q
.sources
.source(*source_id, self.span)
.ok_or(fmt::Error)?;
write!(f, "{}", s)?;
}
CopySource::Inline(c) => {
write!(f, "{:?}", c)?;
}
},
Kind::Number(s) => match s {
NumberSource::Text(text) => {
let s = cx
.idx
.q
.sources
.source(text.source_id, self.span)
.ok_or(fmt::Error)?;
write!(f, "{}", s)?;
}
NumberSource::Synthetic(id) => {
let n = cx.idx.q.storage.get_number(*id).ok_or(fmt::Error)?;
write!(f, "{}", n)?;
}
},
other => {
let s = other.as_literal_str().ok_or(fmt::Error)?;
write!(f, "{}", s)?;
}
}
return Ok(());
struct FormatBytes<'a>(&'a [u8]);
impl fmt::Display for FormatBytes<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "b\"")?;
for b in bytes_escape_default(self.0) {
write!(f, "{}", b as char)?;
}
write!(f, "\"")?;
Ok(())
}
}
fn bytes_escape_default(bytes: &[u8]) -> impl Iterator<Item = u8> + '_ {
bytes.iter().copied().flat_map(ascii::escape_default)
}
}
}
impl fmt::Debug for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}@{:?}", self.kind, self.span)
}
}
impl Parse for Token {
fn parse(p: &mut Parser<'_>) -> compile::Result<Self> {
p.next()
}
}
impl Peek for Token {
fn peek(p: &mut super::prelude::Peeker<'_>) -> bool {
!p.is_eof()
}
}
impl ToTokens for Token {
fn to_tokens(
&self,
_: &mut MacroContext<'_, '_, '_>,
stream: &mut TokenStream,
) -> alloc::Result<()> {
stream.push(*self)
}
}
impl Spanned for Token {
fn span(&self) -> Span {
self.span
}
}
impl IntoExpectation for Token {
fn into_expectation(self) -> Expectation {
self.kind.into_expectation()
}
}
#[derive(Debug, TryClone)]
#[non_exhaustive]
pub enum NumberValue {
Float(f64),
Integer(#[try_clone(with = num::BigInt::clone)] num::BigInt),
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum NumberSize {
S8,
S16,
S32,
S64,
}
impl NumberSize {
pub(crate) fn signed_in(&self, value: i64) -> bool {
self.signed_min() <= value && value <= self.signed_max()
}
pub(crate) fn unsigned_in(&self, value: u64) -> bool {
self.unsigned_min() <= value && value <= self.unsigned_max()
}
pub(crate) fn signed_min(&self) -> i64 {
match self {
Self::S8 => i8::MIN as i64,
Self::S16 => i16::MIN as i64,
Self::S32 => i32::MIN as i64,
Self::S64 => i64::MIN,
}
}
pub(crate) fn signed_max(&self) -> i64 {
match self {
Self::S8 => i8::MAX as i64,
Self::S16 => i16::MAX as i64,
Self::S32 => i32::MAX as i64,
Self::S64 => i64::MAX,
}
}
pub(crate) fn unsigned_min(&self) -> u64 {
match self {
Self::S8 => u8::MIN as u64,
Self::S16 => u16::MIN as u64,
Self::S32 => u32::MIN as u64,
Self::S64 => u64::MIN,
}
}
pub(crate) fn unsigned_max(&self) -> u64 {
match self {
Self::S8 => u8::MAX as u64,
Self::S16 => u16::MAX as u64,
Self::S32 => u32::MAX as u64,
Self::S64 => u64::MAX,
}
}
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum NumberSuffix {
Unsigned(Span, NumberSize),
Signed(Span, NumberSize),
Float(Span),
}
#[derive(Debug, TryClone)]
#[non_exhaustive]
pub struct Number {
pub value: NumberValue,
pub suffix: Option<NumberSuffix>,
}
impl Number {
pub(crate) fn as_u32(&self, neg: bool) -> Option<u32> {
self.as_primitive(neg, num::ToPrimitive::to_u32)
}
pub(crate) fn as_usize(&self, neg: bool) -> Option<usize> {
self.as_primitive(neg, num::ToPrimitive::to_usize)
}
pub(crate) fn as_tuple_index(&self) -> Option<usize> {
use num::ToPrimitive;
match &self.value {
NumberValue::Integer(n) => n.to_usize(),
_ => None,
}
}
fn as_primitive<T>(&self, neg: bool, to: impl FnOnce(&num::BigInt) -> Option<T>) -> Option<T> {
let NumberValue::Integer(number) = &self.value else {
return None;
};
let mut number = number;
let negated;
if neg {
negated = number.clone().neg();
number = &negated;
}
to(number)
}
}
macro_rules! impl_from_int {
($($ty:ty),*) => {
$(
impl From<$ty> for Number {
#[inline]
fn from(value: $ty) -> Self {
Self {
value: NumberValue::Integer(num::BigInt::from(value)),
suffix: None,
}
}
}
)*
};
}
impl_from_int!(usize, isize, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
impl From<f32> for Number {
#[inline]
fn from(value: f32) -> Self {
Self {
value: NumberValue::Float(value as f64),
suffix: None,
}
}
}
impl From<f64> for Number {
#[inline]
fn from(value: f64) -> Self {
Self {
value: NumberValue::Float(value),
suffix: None,
}
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.value {
NumberValue::Float(n) => write!(f, "{}", n),
NumberValue::Integer(n) => write!(f, "{}", n),
}
}
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum NumberBase {
Decimal,
Hex,
Octal,
Binary,
}
impl fmt::Display for NumberBase {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Decimal => write!(fmt, "decimal"),
Self::Hex => write!(fmt, "hex"),
Self::Octal => write!(fmt, "octal"),
Self::Binary => write!(fmt, "binary"),
}
}
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum BuiltIn {
Template,
Format,
BuiltIn,
Literal,
Doc,
}
impl BuiltIn {
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Template => "template",
Self::Format => "formatspec",
Self::BuiltIn => "builtin",
Self::Literal => "literal",
Self::Doc => "doc",
}
}
}
impl fmt::Display for BuiltIn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum LitSource {
Text(SourceId),
Synthetic(SyntheticId),
BuiltIn(BuiltIn),
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum StrSource {
Text(StrText),
Synthetic(SyntheticId),
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub struct StrText {
pub source_id: SourceId,
pub escaped: bool,
pub wrapped: bool,
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum NumberSource {
Text(NumberText),
Synthetic(SyntheticId),
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
#[try_clone(bound = {T: TryClone})]
pub enum CopySource<T>
where
T: Copy,
{
Text(SourceId),
Inline(T),
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub struct NumberText {
pub source_id: SourceId,
pub is_fractional: bool,
pub base: NumberBase,
pub number: Span,
pub suffix: Span,
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum Delimiter {
Parenthesis,
Brace,
Bracket,
Empty,
}
impl Delimiter {
pub(crate) fn open(self) -> &'static str {
match self {
Self::Parenthesis => "(",
Self::Brace => "{",
Self::Bracket => "[",
Self::Empty => "",
}
}
pub(crate) fn close(self) -> &'static str {
match self {
Self::Parenthesis => ")",
Self::Brace => "}",
Self::Bracket => "]",
Self::Empty => "",
}
}
}