use crate::ast::Kind;
use crate::shared::Description;
use crate::{MacroContext, ParseError, ParseErrorKind, Spanned};
use runestick::Span;
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Token {
pub span: Span,
pub kind: Kind,
}
impl Token {
pub fn token_fmt(&self, ctx: &MacroContext, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
Kind::Eof | Kind::Error => {
return Err(fmt::Error);
}
Kind::Ident(s) => match s {
StringSource::Text => {
let s = ctx.source().source(self.span).ok_or_else(|| fmt::Error)?;
write!(f, "{}", s)?;
}
StringSource::Synthetic(id) => {
match ctx.storage().with_string(*id, |s| write!(f, "{}", s)) {
Some(result) => result?,
None => return Err(fmt::Error),
}
}
StringSource::BuiltIn(builtin) => {
write!(f, "{}", builtin)?;
}
},
Kind::Label(s) => match s {
StringSource::Text => {
let s = ctx.source().source(self.span).ok_or_else(|| fmt::Error)?;
write!(f, "{}", s)?;
}
StringSource::Synthetic(id) => {
match ctx.storage().with_string(*id, |s| write!(f, "'{}", s)) {
Some(result) => result?,
None => return Err(fmt::Error),
}
}
StringSource::BuiltIn(builtin) => {
write!(f, "'{}", builtin)?;
}
},
Kind::Byte(s) => match s {
CopySource::Text => {
let s = ctx.source().source(self.span).ok_or_else(|| 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(1)
} else {
self.span
};
let s = ctx.source().source(span).ok_or_else(|| fmt::Error)?;
write!(f, "b\"{}\"", s)?;
}
StrSource::Synthetic(id) => {
match ctx
.storage()
.with_byte_string(*id, |bytes| write!(f, "{}", FormatBytes(bytes)))
{
Some(result) => result?,
None => return Err(fmt::Error),
}
}
},
Kind::Char(s) => match s {
CopySource::Text => {
let s = ctx.source().source(self.span).ok_or_else(|| fmt::Error)?;
write!(f, "{}", s)?;
}
CopySource::Inline(c) => {
write!(f, "{:?}", c)?;
}
},
Kind::Number(s) => match s {
NumberSource::Text(_) => {
let s = ctx.source().source(self.span).ok_or_else(|| fmt::Error)?;
write!(f, "{}", s)?;
}
NumberSource::Synthetic(id) => {
match ctx.storage().with_number(*id, |n| write!(f, "{}", n)) {
Some(result) => result?,
None => return Err(fmt::Error),
}
}
},
Kind::Str(s) => match s {
StrSource::Text(text) => {
let span = if text.wrapped {
self.span.narrow(1)
} else {
self.span
};
let s = ctx.source().source(span).ok_or_else(|| fmt::Error)?;
write!(f, "\"{}\"", s)?;
}
StrSource::Synthetic(id) => {
match ctx.storage().with_string(*id, |s| write!(f, "{:?}", s)) {
Some(result) => result?,
None => return Err(fmt::Error),
}
}
},
other => {
write!(f, "{}", other)?;
}
}
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(std::ascii::escape_default)
}
}
}
impl crate::ToTokens for Token {
fn to_tokens(&self, _: &MacroContext, stream: &mut crate::TokenStream) {
stream.push(*self);
}
}
impl Spanned for Token {
fn span(&self) -> Span {
self.span
}
}
impl Description for &Token {
fn description(self) -> &'static str {
self.kind.description()
}
}
#[derive(Debug, Clone)]
pub enum Number {
Float(f64),
Integer(num::BigInt),
}
impl Number {
pub fn neg(self) -> Self {
use std::ops::Neg as _;
match self {
Self::Float(n) => Self::Float(-n),
Self::Integer(n) => Self::Integer(n.neg()),
}
}
pub fn as_u32(&self, spanned: Span, neg: bool) -> Result<u32, ParseError> {
self.as_primitive(spanned, neg, num::ToPrimitive::to_u32)
}
pub fn as_i64(&self, spanned: Span, neg: bool) -> Result<i64, ParseError> {
self.as_primitive(spanned, neg, num::ToPrimitive::to_i64)
}
pub fn as_usize(&self, spanned: Span, neg: bool) -> Result<usize, ParseError> {
self.as_primitive(spanned, neg, num::ToPrimitive::to_usize)
}
fn as_primitive<T>(
&self,
spanned: Span,
neg: bool,
to: impl FnOnce(&num::BigInt) -> Option<T>,
) -> Result<T, ParseError> {
use std::ops::Neg as _;
let number = match self {
Number::Float(_) => return Err(ParseError::new(spanned, ParseErrorKind::BadNumber)),
Number::Integer(n) => {
if neg {
to(&n.clone().neg())
} else {
to(n)
}
}
};
match number {
Some(n) => Ok(n),
None => Err(ParseError::new(
spanned,
ParseErrorKind::BadNumberOutOfBounds,
)),
}
}
pub fn as_tuple_index(&self) -> Option<usize> {
use num::ToPrimitive as _;
match self {
Self::Integer(n) => n.to_usize(),
_ => None,
}
}
}
macro_rules! impl_from_int {
($ty:ty) => {
impl From<$ty> for Number {
fn from(value: $ty) -> Self {
Self::Integer(num::BigInt::from(value))
}
}
};
}
impl_from_int!(usize);
impl_from_int!(isize);
impl_from_int!(i16);
impl_from_int!(u16);
impl_from_int!(i32);
impl_from_int!(u32);
impl_from_int!(i64);
impl_from_int!(u64);
impl_from_int!(i128);
impl_from_int!(u128);
impl From<f32> for Number {
fn from(value: f32) -> Self {
Self::Float(value as f64)
}
}
impl From<f64> for Number {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Float(n) => write!(f, "{}", n),
Self::Integer(n) => write!(f, "{}", n),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
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, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BuiltIn {
Template,
Format,
BuiltIn,
Literal,
}
impl BuiltIn {
pub fn as_str(self) -> &'static str {
match self {
Self::Template => "template",
Self::Format => "formatspec",
Self::BuiltIn => "builtin",
Self::Literal => "literal",
}
}
}
impl fmt::Display for BuiltIn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum StringSource {
Text,
Synthetic(usize),
BuiltIn(BuiltIn),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum StrSource {
Text(StrText),
Synthetic(usize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StrText {
pub escaped: bool,
pub wrapped: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NumberSource {
Text(NumberText),
Synthetic(usize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CopySource<T>
where
T: Copy,
{
Text,
Inline(T),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NumberText {
pub is_fractional: bool,
pub base: NumberBase,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Delimiter {
Parenthesis,
Brace,
Bracket,
}
impl Delimiter {
pub fn open(self) -> &'static str {
match self {
Self::Parenthesis => "(",
Self::Brace => "{",
Self::Bracket => "[",
}
}
pub fn close(self) -> &'static str {
match self {
Self::Parenthesis => ")",
Self::Brace => "}",
Self::Bracket => "]",
}
}
}