Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/mbe/src/lib.rs')
-rw-r--r--crates/mbe/src/lib.rs61
1 files changed, 44 insertions, 17 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 9f9fa36abd..936cf178f0 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -14,6 +14,7 @@ extern crate ra_ap_rustc_lexer as rustc_lexer;
extern crate rustc_lexer;
mod expander;
+mod macro_call_style;
mod parser;
#[cfg(test)]
@@ -29,6 +30,7 @@ use tt::iter::TtIter;
use std::fmt;
use std::sync::Arc;
+pub use crate::macro_call_style::{MacroCallStyle, MacroCallStyles};
use crate::parser::{MetaTemplate, MetaVarKind, Op};
pub use tt::{Delimiter, DelimiterKind, Punct};
@@ -137,6 +139,8 @@ pub struct DeclarativeMacro {
#[derive(Clone, Debug, PartialEq, Eq)]
struct Rule {
+ /// Is this a normal fn-like rule, an `attr()` rule, or a `derive()` rule?
+ style: MacroCallStyle,
lhs: MetaTemplate,
rhs: MetaTemplate,
}
@@ -148,7 +152,7 @@ impl DeclarativeMacro {
/// The old, `macro_rules! m {}` flavor.
pub fn parse_macro_rules(
- tt: &tt::TopSubtree<Span>,
+ tt: &tt::TopSubtree,
ctx_edition: impl Copy + Fn(SyntaxContext) -> Edition,
) -> DeclarativeMacro {
// Note: this parsing can be implemented using mbe machinery itself, by
@@ -187,21 +191,26 @@ impl DeclarativeMacro {
/// The new, unstable `macro m {}` flavor.
pub fn parse_macro2(
- args: Option<&tt::TopSubtree<Span>>,
- body: &tt::TopSubtree<Span>,
+ args: Option<&tt::TopSubtree>,
+ body: &tt::TopSubtree,
ctx_edition: impl Copy + Fn(SyntaxContext) -> Edition,
) -> DeclarativeMacro {
let mut rules = Vec::new();
let mut err = None;
if let Some(args) = args {
+ // The presence of an argument list means that this macro uses the
+ // "simple" syntax, where the body is the RHS of a single rule.
cov_mark::hit!(parse_macro_def_simple);
let rule = (|| {
let lhs = MetaTemplate::parse_pattern(ctx_edition, args.iter())?;
let rhs = MetaTemplate::parse_template(ctx_edition, body.iter())?;
- Ok(crate::Rule { lhs, rhs })
+ // In the "simple" syntax, there is apparently no way to specify
+ // that the single rule is an attribute or derive rule, so it
+ // must be a function-like rule.
+ Ok(crate::Rule { style: MacroCallStyle::FnLike, lhs, rhs })
})();
match rule {
@@ -209,6 +218,8 @@ impl DeclarativeMacro {
Err(e) => err = Some(Box::new(e)),
}
} else {
+ // There was no top-level argument list, so this macro uses the
+ // list-of-rules syntax, similar to `macro_rules!`.
cov_mark::hit!(parse_macro_def_rules);
let mut src = body.iter();
while !src.is_empty() {
@@ -249,22 +260,39 @@ impl DeclarativeMacro {
self.rules.len()
}
+ pub fn rule_styles(&self) -> MacroCallStyles {
+ if self.rules.is_empty() {
+ // No rules could be parsed, so fall back to assuming that this
+ // is intended to be a function-like macro.
+ MacroCallStyles::FN_LIKE
+ } else {
+ self.rules
+ .iter()
+ .map(|rule| MacroCallStyles::from(rule.style))
+ .fold(MacroCallStyles::empty(), |a, b| a | b)
+ }
+ }
+
pub fn expand(
&self,
- tt: &tt::TopSubtree<Span>,
+ db: &dyn salsa::Database,
+ tt: &tt::TopSubtree,
marker: impl Fn(&mut Span) + Copy,
+ call_style: MacroCallStyle,
call_site: Span,
- def_site_edition: Edition,
- ) -> ExpandResult<(tt::TopSubtree<Span>, MatchedArmIndex)> {
- expander::expand_rules(&self.rules, tt, marker, call_site, def_site_edition)
+ ) -> ExpandResult<(tt::TopSubtree, MatchedArmIndex)> {
+ expander::expand_rules(db, &self.rules, tt, marker, call_style, call_site)
}
}
impl Rule {
fn parse(
edition: impl Copy + Fn(SyntaxContext) -> Edition,
- src: &mut TtIter<'_, Span>,
+ src: &mut TtIter<'_>,
) -> Result<Self, ParseError> {
+ // Parse an optional `attr()` or `derive()` prefix before the LHS pattern.
+ let style = parser::parse_rule_style(src)?;
+
let (_, lhs) =
src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?;
@@ -275,7 +303,7 @@ impl Rule {
let lhs = MetaTemplate::parse_pattern(edition, lhs)?;
let rhs = MetaTemplate::parse_template(edition, rhs)?;
- Ok(crate::Rule { lhs, rhs })
+ Ok(crate::Rule { style, lhs, rhs })
}
}
@@ -362,16 +390,15 @@ impl<T: Default, E> From<Result<T, E>> for ValueResult<T, E> {
}
pub fn expect_fragment<'t>(
- tt_iter: &mut TtIter<'t, Span>,
+ db: &dyn salsa::Database,
+ tt_iter: &mut TtIter<'t>,
entry_point: ::parser::PrefixEntryPoint,
- edition: ::parser::Edition,
- delim_span: DelimSpan<Span>,
-) -> ExpandResult<tt::TokenTreesView<'t, Span>> {
+ delim_span: DelimSpan,
+) -> ExpandResult<tt::TokenTreesView<'t>> {
use ::parser;
let buffer = tt_iter.remaining();
- // FIXME: Pass the correct edition per token. Due to the split between mbe and hir-expand it's complicated.
- let parser_input = to_parser_input(buffer, &mut |_ctx| edition);
- let tree_traversal = entry_point.parse(&parser_input, edition);
+ let parser_input = to_parser_input(buffer, &mut |ctx| ctx.edition(db));
+ let tree_traversal = entry_point.parse(&parser_input);
let mut cursor = buffer.cursor();
let mut error = false;
for step in tree_traversal.iter() {