Skip to content

Commit

Permalink
add derive macro for Spanned
Browse files Browse the repository at this point in the history
  • Loading branch information
sam0x17 committed Apr 1, 2024
1 parent 5b4c868 commit 7b38e09
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 80 deletions.
61 changes: 60 additions & 1 deletion quoth-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use quote::{quote, ToTokens};
use syn::{parse2, spanned::Spanned, Error, Item, Result};

/// Derives [`Display`](core::fmt::Display) and [`FromStr`](core::str::FromStr) based on the
Expand Down Expand Up @@ -39,3 +39,62 @@ fn derive_parsable_ext_internal(tokens: TokenStream2) -> Result<TokenStream2> {
};
Ok(tokens)
}

/// Automatically derives `Spanned` for the annotated type. This will work as long as there is
/// some struct field of type `Span`.
#[proc_macro_derive(Spanned)]
pub fn derive_spanned(tokens: TokenStream) -> TokenStream {
match derive_spanned_internal(tokens.into()) {
Ok(tokens) => tokens,
Err(err) => err.to_compile_error(),
}
.into()
}

fn derive_spanned_internal(tokens: TokenStream2) -> Result<TokenStream2> {
let item = parse2::<Item>(tokens)?;
let (field_name, ident, generics) = match item {
// Item::Enum(item_enum) => (item_enum.ident, item_enum.generics),
Item::Struct(item_struct) => {
let mut i: usize = 0;
let field_name = item_struct
.fields
.iter()
.find_map(|field| {
i += 1;
if field
.ty
.to_token_stream()
.to_string()
.trim()
.ends_with("Span")
|| field.ident.to_token_stream().to_string().trim() == "span"
{
if let Some(ident) = field.ident.as_ref() {
Some(quote!(self.#ident))
} else {
let lit = syn::Index::from(i - 1);
Some(quote!(self.#lit))
}
} else {
None
}
})
.ok_or_else(|| {
Error::new(item_struct.span(), "expected a field of type `quoth::Span`")
})?
.clone();
(field_name, item_struct.ident, item_struct.generics)
}
_ => return Err(Error::new(item.span(), "expected struct")),
};
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let tokens = quote! {
impl #impl_generics quoth::Spanned for #ident #ty_generics #where_clause {
fn span(&self) -> quoth::Span {
#field_name.clone()
}
}
};
Ok(tokens)
}
10 changes: 3 additions & 7 deletions src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt::Display;

use crate as quoth;

use super::*;

/// Represents the severity of a [`Diagnostic`].
Expand Down Expand Up @@ -53,7 +55,7 @@ impl Display for DiagnosticLevel {
/// );
/// println!("{}", diag);
/// ```
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
#[derive(Clone, PartialEq, Eq, Debug, Hash, Spanned)]
pub struct Diagnostic {
level: DiagnosticLevel,
span: Span,
Expand Down Expand Up @@ -137,12 +139,6 @@ impl Diagnostic {
}
}

impl Spanned for Diagnostic {
fn span(&self) -> Span {
self.span.clone()
}
}

impl Display for Diagnostic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let level = self.level;
Expand Down
8 changes: 1 addition & 7 deletions src/parsable/everything.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,9 @@ use super::*;

use crate as quoth;

#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt, Spanned)]
pub struct Everything(Span);

impl Spanned for Everything {
fn span(&self) -> Span {
self.0.clone()
}
}

impl Parsable for Everything {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let span = Span::new(
Expand Down
8 changes: 1 addition & 7 deletions src/parsable/exact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::*;

use crate as quoth;

#[derive(Clone, Debug, Hash, PartialEq, Eq, ParsableExt)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, ParsableExt, Spanned)]
pub struct Exact(pub Span);

impl Exact {
Expand All @@ -19,12 +19,6 @@ impl Exact {
}
}

impl Spanned for Exact {
fn span(&self) -> Span {
self.0.clone()
}
}

impl Parsable for Exact {
fn parse(stream: &mut ParseStream) -> Result<Self> {
Ok(Exact(Span::new(
Expand Down
8 changes: 1 addition & 7 deletions src/parsable/nothing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,9 @@ use super::*;

use crate as quoth;

#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt, Spanned)]
pub struct Nothing(Span);

impl Spanned for Nothing {
fn span(&self) -> Span {
self.0.clone()
}
}

impl Parsable for Nothing {
fn parse(stream: &mut ParseStream) -> Result<Self> {
if stream.position < stream.source().len() {
Expand Down
40 changes: 5 additions & 35 deletions src/parsable/numbers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use super::*;
// enables usage of quoth proc macros within quoth
use crate as quoth;

#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt, Spanned)]
pub struct U64(u64, Span);

impl U64 {
Expand All @@ -14,12 +14,6 @@ impl U64 {
}
}

impl Spanned for U64 {
fn span(&self) -> Span {
self.1.clone()
}
}

impl Parsable for U64 {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let mut digits = Vec::new();
Expand Down Expand Up @@ -66,7 +60,7 @@ impl From<U64> for i128 {
}
}

#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt, Spanned)]
pub struct U128(u128, Span);

impl U128 {
Expand All @@ -75,12 +69,6 @@ impl U128 {
}
}

impl Spanned for U128 {
fn span(&self) -> Span {
self.1.clone()
}
}

impl Parsable for U128 {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let mut digits = Vec::new();
Expand Down Expand Up @@ -114,7 +102,7 @@ impl From<U128> for u128 {
value.0
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt, Spanned)]
pub struct I64(i64, Span);

impl I64 {
Expand All @@ -123,12 +111,6 @@ impl I64 {
}
}

impl Spanned for I64 {
fn span(&self) -> Span {
self.1.clone()
}
}

impl Parsable for I64 {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let mut digits = Vec::new();
Expand Down Expand Up @@ -174,7 +156,7 @@ impl From<I64> for i128 {
}
}

#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, ParsableExt, Spanned)]
pub struct I128(i128, Span);

impl I128 {
Expand All @@ -183,12 +165,6 @@ impl I128 {
}
}

impl Spanned for I128 {
fn span(&self) -> Span {
self.1.clone()
}
}

impl Parsable for I128 {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let mut digits = Vec::new();
Expand Down Expand Up @@ -234,7 +210,7 @@ impl From<I64> for I128 {
}
}

#[derive(Clone, PartialEq, Eq, Debug, Hash, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Debug, Hash, ParsableExt, Spanned)]
pub struct Decimal(rust_decimal::Decimal, Span);

impl Decimal {
Expand Down Expand Up @@ -262,12 +238,6 @@ impl From<Decimal> for rust_decimal::Decimal {
}
}

impl Spanned for Decimal {
fn span(&self) -> Span {
self.1.clone()
}
}

impl Parsable for Decimal {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let start_position = stream.position;
Expand Down
8 changes: 1 addition & 7 deletions src/parsable/whitespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,9 @@ use super::*;

use crate as quoth;

#[derive(Clone, PartialEq, Eq, Debug, Hash, ParsableExt)]
#[derive(Clone, PartialEq, Eq, Debug, Hash, ParsableExt, Spanned)]
pub struct Whitespace(Span);

impl Spanned for Whitespace {
fn span(&self) -> Span {
self.0.clone()
}
}

impl Parsable for Whitespace {
fn parse(stream: &mut ParseStream) -> Result<Self> {
let start_position = stream.position;
Expand Down
15 changes: 6 additions & 9 deletions src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,11 @@ pub fn common_prefix(s1: &str, s2: &str) -> String {
/// Types that can be parsed using Quoth must implement this trait.
///
/// Note that to satisfy the requirements of [`Parsable`], implementers should implement
/// [`Parsable`] and [`Spanned`] on the type directly, and derive [`ParsableExt`] on the type
/// to get suitable, required impls for [`FromStr`] and [`Display`].
/// [`Parsable`] on the type directly, and derive [`ParsableExt`] on the type
/// to get suitable, required impls for [`FromStr`] and [`Display`] as well as [`Spanned`].
///
/// Note that [`Spanned`] must be implemented manually if the underlying span is not simply a
/// struct field of type [`Span`].
///
/// It is undefined behavior to manually implement [`FromStr`] and [`Display`] on a
/// [`Parsable`] such that they do not correspond with [`Parsable::parse`] and
Expand All @@ -444,7 +447,7 @@ pub fn common_prefix(s1: &str, s2: &str) -> String {
/// ```
/// use quoth::*;
///
/// #[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt)]
/// #[derive(Clone, Debug, PartialEq, Eq, Hash, ParsableExt, Spanned)]
/// pub struct Where(Span);
///
/// impl Parsable for Where {
Expand All @@ -453,12 +456,6 @@ pub fn common_prefix(s1: &str, s2: &str) -> String {
/// }
/// }
///
/// impl Spanned for Where {
/// fn span(&self) -> Span {
/// self.0.clone()
/// }
/// }
///
/// let mut stream = ParseStream::from("where are you");
/// let parsed = stream.parse::<Where>().unwrap();
/// assert_eq!(parsed.span().source_text(), "where");
Expand Down

0 comments on commit 7b38e09

Please sign in to comment.