#logo #display #macro-derive #macro #debugging #string

macro logos-display

A derive macro to automatically define the Display trait based on logos token and regex attributes

3 releases

0.1.3 Aug 11, 2024
0.1.2 Sep 6, 2023
0.1.1 Sep 6, 2023
0.1.0 Jul 15, 2023

#1960 in Encoding

Download history 10/week @ 2024-07-01 7/week @ 2024-07-15 21/week @ 2024-07-29 73/week @ 2024-08-05 55/week @ 2024-08-12 3/week @ 2024-08-19 25/week @ 2024-08-26 4/week @ 2024-09-09 11/week @ 2024-09-16 40/week @ 2024-09-23 15/week @ 2024-09-30 2/week @ 2024-10-07 14/week @ 2024-10-14

71 downloads per month
Used in 4 crates (via wagon-lexer)

MIT license

21KB
408 lines

Logos Display

A set of derive macros that automatically implement Display and Debug for an enum, based on the Logos token and regex attributes. Usable in no_std contexts.

How To Use

Simply use logos_display::Display and/or use logos_display::Debug and add it to your derives, like so:

use logos_display::{Display, Debug}
#[derive(Display, Debug, Logos)]
enum A {
	#[token("{")]
	LCur,

	#[regex("[a-z]")]
	Lower
}

|
V

impl core::fmt::Display for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "{"),
            A::Lower => write!(f, "{}", "[a-z]"),
        }
    }
}

Difference between Display and Debug

If the enum variant is a unit type, there is no difference. But in the case where the variant is a tuple or struct variant, the Debug version will also show the inner value held by the instance, whereas the Display version will only output the name of the outer layer. Like so:

use logos_display::{Display, Debug}
#[derive(Display, Debug, Logos)]
enum A {
	#[token("{")]
	LCur,

	#[regex("[a-z]", |lex| some_func(lex.slice()))]
	Lower(TypeOne, TypeTwo)
}

|
V

impl core::fmt::Debug for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "{"),
            A::Lower(_arg1, _arg2) => write!(f, "{}{:?}", "[a-z]", vec![_arg1, _arg2]),
        }
    }
}

This does of course require the inner types to implement Debug in some form as well.

Dealing with non-tokens

In the case that a variant is not a token or regex, the name of the variant will be used for the Display method (so variant B will have "B" as it's string representation). If you want to override any of this functionality, you can add an display_override("string") attribute to the variant as follows:

use logos_display::Display
#[derive(Display, Logos)]
enum A {
	#[display_override("fancy curly thing")]
	#[token("{")]
	LCur,

	#[regex("[a-z]")]
	Lower
}

|
V

impl core::fmt::Display for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "fancy curly thing"),
            A::Lower => write!(f, "{}", "[a-z]"),
        }
    }
}

Multiple tokens

When a variant accepts multiple tokens, by default, they will be concatenated using / in the string representation, like so:

use logos_display::Display
#[derive(Display, Logos)]
enum A {
	#[token("{")]
	#[token("}")]
	Cur
}

|
V

impl core::fmt::Display for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "{/}"),
        }
    }
}

This functionality can be overwritten using the display_concat("string") attribute on the original enum:

use logos_display::Display
#[derive(Display, Logos)]
#[display_concat(" or ")]
enum A {
	#[token("{")]
	#[token("}")]
	Cur
}

|
V

impl core::fmt::Display for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "{ or }"),
        }
    }
}

Additionally, you can pass None to this attribute in order to disable concatonation. In this case, the token that is encountered last will be used:

use logos_display::Display
#[derive(Display, Logos)]
#[display_concat(None)]
enum A {
	#[token("{")]
	#[token("}")]
	Cur
}

|
V

impl core::fmt::Display for A {
	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
		use core::fmt::Write;
        match &self {
            A::LCur => write!(f, "{}", "}"),
        }
    }
}

Dependencies

~245–690KB
~17K SLoC