macroex
An extractor based low level macro parsing crate that provides high level parsing support through derive macros.
FromMacro
and Extractor
[FromMacro
] is the bread and butter of this crate.
FromMacro
provides a from_one
and a from_many
function
that parses a [TokenTree
] and a [TokenStream
] respectively.
We can mostly assume from_many
will contain two or more TokenTrees
. If not
that is considered a bug in an extractor.
All implementors of FromMacro
are Extractors
of one TokenTree
. When used on a
TokenStream
iterator directly, they will consume a single TokenTree
and try to parse it using from_one
.
let mut iter = quote!.into_iter;
let a: i32 = iter.extract?;
let b: Punct = iter.extract?;
// Extracts a string value from an ident
let IdentString = iter.extract?;
// Validates a semicolon
let d: '> = iter.extract?;
let e: bool = iter.extract?;
// Validates a false literal
let f: LitFalse = iter.extract?;
This is pretty great! As most things can be represented as a single [TokenTree
].
// This is a single TokenTree::Group
However there are other things one TokenTree
cannot account for.
// This fails because -45 is two tokens
let a: i32 = quote!.into_iter.extract.unwrap;
Wrapping [FromMacro
] implementers in other Extractors
allow FromMacro
implementors to parse additional TokenTrees
and
potentially utilize the from_many
method
if more than one TokenTree
is matched.
// Note -45 is two tokens
let mut iter = quote!.into_iter;
// All extracts everything from a stream
let All = iter.extract?;
assert_eq!;
let mut iter = quote!.into_iter;
// CommaExtractor extracts until a comma or end of stream is found.
let CommaExtractor = iter.extract?;
let CommaExtractor = iter.extract?;
let CommaExtractor = iter.extract?;
// EndOfStream is a unit struct extractor and this asserts iter is empty
let EndOfStream = iter.extract?;
assert_eq!;
assert_eq!;
assert_eq!;
Derive
We provide derive macro FromMacro
and [FromAttrs
] that functions similarly to
to serde::Deserialize
. This enables ergonomic
parsing for structs and enums following a specific data format.
FromMacro
parses syntax similar to native rust,
while [FromAttrs
] parses syntax commonly used in macro attributes.
Why not serde_tokenstream
?
Since we do not use the serde
data model. Our data model is much more powerful in the macro context.
We are allowed to extract all [FromMacro
] implementors,
including [TokenStream
], Ident
, Group
, etc.
FromMacro
FromMacro
parses syntax similar to native rust.
Type | from_one |
from_many |
---|---|---|
Unit Struct | StructName |
-- |
Tuple Struct | (tuple, ..) |
StructName (tuple, ..) |
Named Struct | {field: value, ..} |
StructName {field: value, ..} |
Unit Enum Variant | VariantName |
-- |
Tuple Enum Variant | -- | VariantName (tuple, ..) |
Named Enum Variant | -- | VariantName {field: value, ..} |
Examples
Type | Rust Type | from_one |
from_many |
---|---|---|---|
Unit Struct | struct Red; |
Red |
-- |
Tuple Struct | struct Vec2 (i32, i32) |
(4, 5) |
Vec2 (4, 5) |
Named Struct | struct Vec2 {x: i32, y: i32} |
{x: 4, y: 5} |
Vec2 {x: 4, y: 5} |
Unit Variant | enum Color {Black, White} |
Black |
-- |
Tuple Variant | enum Animals {Dog(String), Sheep(usize)} |
-- | Dog ("Rex") |
Named Variant | enum Shapes {Square {x: f32}, Rect {x: f32, y: f32}} |
-- | Rect {x: 4, y: 5} |
Use Case
Since we are likely to be parsing configurations in macros,
we supply a Default::default()
value if a field is not found.
You are required to opt out of this with #[macroex(required)]
if
your type does not implement [Default
].
Example macro input:
person!
Attributes
The [FromMacro
] macro supports the following attributes:
// We use the same casing names as serde.
FromAttrs
[FromAttrs
]
Generates a simple [FromMacro
] implementation for syntax commonly associated with macro attributes.
This macro is only allowed on named structs and supports 3 basic syntax:
.., name, ..
parses toname: true
, which matches a boolean value..., name = expr, ..
parses toname: expr
.., name(..), ..
parses toname: T{ .. }
Other types like fieldless enums can potentially use FromMacro
to generated compatible [FromMacro
] implementations to use with this macro.
Example
We use the same set of attributes as [FromMacro
]
Example attribute:
We can parse either
with from_one
, or
name = "Ferris", species = Crab, mascot
with from_many
, commonly extracted with syn
.
Macro Chaining and Hygeine
We treat our input as string-like and we will try
to flatten all None
delimited groups encountered during parsing.