Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro invocations + macro_rules! #50

Merged
merged 1 commit into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/parse.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::Error;
use crate::parse_fn::consume_macro;
use crate::parse_impl::{
consume_either_fn_type_const_static_impl, parse_const_or_static, parse_impl, parse_trait,
};
Expand Down Expand Up @@ -218,13 +219,17 @@ pub fn consume_declaration(tokens: &mut Peekable<IntoIter>) -> Result<Declaratio
consume_either_fn_type_const_static_impl(tokens, attributes, vis_marker, "declaration")
}
Some(token) => {
panic!(
"cannot parse declaration: expected keyword struct/enum/union/type/trait/impl/mod/default/const/async/unsafe/extern/fn/static, found token {:?}",
token
);
if let Some(macro_) = consume_macro(tokens, attributes) {
Declaration::Macro(macro_)
} else {
panic!(
"cannot parse declaration: expected keyword struct/enum/union/type/trait/impl/mod/default/const/async/unsafe/extern/fn/static or macro, found token {:?}",
token
);
}
}
None => {
panic!("cannot parse type: expected keyword struct/enum/union/type/trait/impl/mod/default/const/async/unsafe/extern/fn/static, found end-of-stream");
panic!("cannot parse type: expected keyword struct/enum/union/type/trait/impl/mod/default/const/async/unsafe/extern/fn/static or macro, found end-of-stream");
}
};
Ok(declaration)
Expand Down
58 changes: 51 additions & 7 deletions src/parse_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use crate::parse_type::{
consume_declaration_name, consume_field_type, consume_generic_params, consume_where_clause,
};
use crate::parse_utils::{
consume_comma, consume_ident, consume_outer_attributes, consume_punct, consume_stuff_until,
parse_any_ident, parse_punct,
consume_any_ident, consume_comma, consume_ident, consume_outer_attributes, consume_punct,
consume_stuff_until, parse_any_ident, parse_punct,
};
use crate::punctuated::Punctuated;
use crate::types::{
FnParam, FnQualifiers, FnReceiverParam, FnTypedParam, Function, GroupSpan, TyExpr,
};
use crate::{Attribute, VisMarker};
use crate::{Attribute, Macro, VisMarker};
use proc_macro2::{Delimiter, Ident, Punct, TokenStream, TokenTree};
use std::iter::Peekable;

Expand Down Expand Up @@ -118,7 +118,7 @@ fn consume_fn_return(tokens: &mut TokenIter) -> Option<([Punct; 2], TyExpr)> {
Some((
[dash, tip],
TyExpr {
tokens: (consume_stuff_until(
tokens: consume_stuff_until(
tokens,
|token| match token {
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => true,
Expand All @@ -127,7 +127,7 @@ fn consume_fn_return(tokens: &mut TokenIter) -> Option<([Punct; 2], TyExpr)> {
_ => false,
},
true,
)),
),
},
))
}
Expand Down Expand Up @@ -187,7 +187,7 @@ pub(crate) fn consume_fn(
TokenTree::Group(group) if group.delimiter() == Delimiter::Parenthesis => {
(parse_fn_params(group.stream()), GroupSpan::new(&group))
}
_ => panic!("cannot parse function"),
_ => panic!("cannot parse function; missing parameter list"),
};

let (tk_return_arrow, return_ty) = if let Some((arrow, ty)) = consume_fn_return(tokens) {
Expand All @@ -203,7 +203,7 @@ pub(crate) fn consume_fn(
(Some(group.clone()), None)
}
TokenTree::Punct(punct) if punct.as_char() == ';' => (None, Some(punct.clone())),
_ => panic!("cannot parse function"),
_ => panic!("cannot parse function; missing body or `;`"),
};

Ok(Function {
Expand All @@ -222,3 +222,47 @@ pub(crate) fn consume_fn(
body: function_body,
})
}

pub(crate) fn consume_macro(tokens: &mut TokenIter, attributes: Vec<Attribute>) -> Option<Macro> {
// TODO consider multiple-lookahead instead of potentially cloning many tokens
let before_start = tokens.clone();

match consume_macro_inner(tokens, attributes) {
Some(macro_) => Some(macro_),
None => {
// rollback iterator, could be start of const declaration
*tokens = before_start;
None
}
}
}

fn consume_macro_inner(tokens: &mut TokenIter, attributes: Vec<Attribute>) -> Option<Macro> {
let name = consume_any_ident(tokens)?;
let tk_bang = consume_punct(tokens, '!')?;
let tk_declared_name = consume_any_ident(tokens);

let (is_paren, macro_body) = match tokens.next().expect("unexpected end of macro") {
TokenTree::Group(group) if group.delimiter() == Delimiter::Parenthesis => (true, group),
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => (false, group),
_ => panic!("cannot parse macro; missing `{{}}` or `()` group"),
};

let inner_tokens = macro_body.stream().into_iter().collect();

let tk_semicolon = if is_paren {
Some(parse_punct(tokens, ';', "macro invocation semicolon"))
} else {
None
};

Some(Macro {
attributes,
name,
tk_bang,
tk_declared_name,
tk_braces_or_parens: GroupSpan::new(&macro_body),
inner_tokens,
tk_semicolon,
})
}
18 changes: 16 additions & 2 deletions src/parse_impl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::parse_fn::{consume_fn, NotFunction};
use crate::parse_fn::{consume_fn, consume_macro, NotFunction};
use crate::parse_mod::parse_mod;
use crate::parse_type::{consume_bound, consume_generic_params, consume_where_clause};
use crate::parse_utils::{
Expand All @@ -9,6 +9,7 @@ use crate::types::{Constant, ImplMember, TyDefinition, ValueExpr};
use crate::types_edition::GroupSpan;
use crate::{Attribute, Declaration, Impl, Trait, TraitMember, TyExpr, VisMarker};
use proc_macro2::{Delimiter, Group, TokenTree};
use quote::ToTokens;
use std::iter::Peekable;

type TokenIter = Peekable<proc_macro2::token_stream::IntoIter>;
Expand Down Expand Up @@ -149,7 +150,18 @@ pub(crate) fn consume_either_fn_type_const_static_impl(
}
}
}
_ => panic!("unsupported {} item `{}`", context, ident),
ident => {
if let Some(vis_marker) = vis_marker {
panic!(
"unsupported visibility marker `{}`",
vis_marker.to_token_stream()
);
}
match consume_macro(tokens, attributes.clone()) {
Some(macro_) => Declaration::Macro(macro_),
None => panic!("unsupported {} item `{}`", context, ident),
}
}
}
} else {
panic!("unsupported {} element: {:?}", context, tokens.peek())
Expand Down Expand Up @@ -177,6 +189,7 @@ pub(crate) fn parse_impl_body(token_group: Group) -> (GroupSpan, Vec<Attribute>,
Declaration::Function(function) => ImplMember::Method(function),
Declaration::Constant(constant) => ImplMember::Constant(constant),
Declaration::TyDefinition(ty_def) => ImplMember::AssocTy(ty_def),
Declaration::Macro(macro_) => ImplMember::Macro(macro_),
_ => panic!("unsupported impl item `{:?}`", tokens.peek()),
};

Expand Down Expand Up @@ -279,6 +292,7 @@ pub(crate) fn parse_trait(
ImplMember::Method(function) => TraitMember::Method(function),
ImplMember::Constant(constant) => TraitMember::Constant(constant),
ImplMember::AssocTy(assoc_ty) => TraitMember::AssocTy(assoc_ty),
ImplMember::Macro(macro_) => TraitMember::Macro(macro_),
})
.collect();

Expand Down
11 changes: 11 additions & 0 deletions src/parse_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ pub(crate) fn parse_ident(tokens: &mut TokenIter, expected: &str, panic_context:
}
}

pub(crate) fn consume_any_ident(tokens: &mut TokenIter) -> Option<Ident> {
match tokens.peek() {
Some(TokenTree::Ident(ident)) => {
let ident = ident.clone();
tokens.next();
Some(ident)
}
_ => None,
}
}

pub(crate) fn consume_ident(tokens: &mut TokenIter, expected: &str) -> Option<Ident> {
match tokens.peek() {
Some(TokenTree::Ident(ident)) if ident == expected => {
Expand Down
87 changes: 87 additions & 0 deletions src/snapshots/venial__tests__parse_impl_inherent.snap
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,93 @@ Impl(
},
},
),
Macro(
Macro {
attributes: [
Attribute {
tk_hash: Punct {
char: '#',
spacing: Alone,
},
tk_brackets: [],
path: [
clippy,
":",
":",
allow,
],
value: Group(
[
venial,
],
(),
),
},
],
name: Ident(
fn_macro,
),
tk_bang: Punct {
char: '!',
spacing: Alone,
},
tk_declared_name: None,
tk_braces_or_parens: (),
inner_tokens: [
Ident {
sym: MyTrait,
},
],
tk_semicolon: Some(
Punct {
char: ';',
spacing: Alone,
},
),
},
),
Macro(
Macro {
attributes: [],
name: Ident(
block_macro,
),
tk_bang: Punct {
char: '!',
spacing: Alone,
},
tk_declared_name: None,
tk_braces_or_parens: {},
inner_tokens: [
Ident {
sym: fn,
},
Ident {
sym: inner_fn,
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
},
Punct {
char: '-',
spacing: Joint,
},
Punct {
char: '>',
spacing: Alone,
},
Ident {
sym: bool,
},
Punct {
char: ';',
spacing: Alone,
},
],
tk_semicolon: None,
},
),
],
},
)
87 changes: 87 additions & 0 deletions src/snapshots/venial__tests__parse_impl_trait.snap
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,93 @@ Impl(
},
},
),
Macro(
Macro {
attributes: [
Attribute {
tk_hash: Punct {
char: '#',
spacing: Alone,
},
tk_brackets: [],
path: [
clippy,
":",
":",
allow,
],
value: Group(
[
venial,
],
(),
),
},
],
name: Ident(
fn_macro,
),
tk_bang: Punct {
char: '!',
spacing: Alone,
},
tk_declared_name: None,
tk_braces_or_parens: (),
inner_tokens: [
Ident {
sym: MyTrait,
},
],
tk_semicolon: Some(
Punct {
char: ';',
spacing: Alone,
},
),
},
),
Macro(
Macro {
attributes: [],
name: Ident(
block_macro,
),
tk_bang: Punct {
char: '!',
spacing: Alone,
},
tk_declared_name: None,
tk_braces_or_parens: {},
inner_tokens: [
Ident {
sym: fn,
},
Ident {
sym: inner_fn,
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
},
Punct {
char: '-',
spacing: Joint,
},
Punct {
char: '>',
spacing: Alone,
},
Ident {
sym: bool,
},
Punct {
char: ';',
spacing: Alone,
},
],
tk_semicolon: None,
},
),
],
},
)
Loading
Loading