mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Resolve whether $pat is $pat_param or not via 🌟hygiene🌟
This commit is contained in:
parent
7e88fa5d3a
commit
6d1071962f
7 changed files with 158 additions and 54 deletions
|
@ -1449,6 +1449,7 @@ ok!();
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_std_matches() {
|
fn test_new_std_matches() {
|
||||||
check(
|
check(
|
||||||
|
//- edition:2021
|
||||||
r#"
|
r#"
|
||||||
macro_rules! matches {
|
macro_rules! matches {
|
||||||
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
|
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
|
||||||
|
@ -1480,6 +1481,90 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hygienic_pat() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /new.rs crate:new deps:old edition:2015
|
||||||
|
old::make!();
|
||||||
|
fn main() {
|
||||||
|
matches!(0, 0 | 1 if true);
|
||||||
|
}
|
||||||
|
//- /old.rs crate:old edition:2021
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make {
|
||||||
|
() => {
|
||||||
|
macro_rules! matches {
|
||||||
|
($expression:expr, $pattern:pat if $guard:expr ) => {
|
||||||
|
match $expression {
|
||||||
|
$pattern if $guard => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
macro_rules !matches {
|
||||||
|
($expression: expr, $pattern: pat if $guard: expr) = > {
|
||||||
|
match $expression {
|
||||||
|
$pattern if $guard = > true , _ = > false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
match 0 {
|
||||||
|
0|1 if true =>true , _=>false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /new.rs crate:new deps:old edition:2021
|
||||||
|
old::make!();
|
||||||
|
fn main() {
|
||||||
|
matches/*+errors*/!(0, 0 | 1 if true);
|
||||||
|
}
|
||||||
|
//- /old.rs crate:old edition:2015
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make {
|
||||||
|
() => {
|
||||||
|
macro_rules! matches {
|
||||||
|
($expression:expr, $pattern:pat if $guard:expr ) => {
|
||||||
|
match $expression {
|
||||||
|
$pattern if $guard => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
macro_rules !matches {
|
||||||
|
($expression: expr, $pattern: pat if $guard: expr) = > {
|
||||||
|
match $expression {
|
||||||
|
$pattern if $guard = > true , _ = > false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
/* error: unexpected token in input *//* parse error: expected expression */
|
||||||
|
/* parse error: expected FAT_ARROW */
|
||||||
|
/* parse error: expected `,` */
|
||||||
|
/* parse error: expected pattern */
|
||||||
|
match 0 {
|
||||||
|
0 if $guard=>true , _=>false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dollar_crate_lhs_is_not_meta() {
|
fn test_dollar_crate_lhs_is_not_meta() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use base_db::{CrateId, VersionReq};
|
use base_db::{CrateId, VersionReq};
|
||||||
use span::{Edition, MacroCallId, Span};
|
use span::{MacroCallId, Span, SyntaxContextId};
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
attrs::RawAttrs,
|
attrs::RawAttrs,
|
||||||
db::ExpandDatabase,
|
db::ExpandDatabase,
|
||||||
hygiene::{apply_mark, Transparency},
|
hygiene::{apply_mark, Transparency},
|
||||||
tt, AstId, ExpandError, ExpandResult,
|
tt, AstId, ExpandError, ExpandResult, Lookup,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Old-style `macro_rules` or the new macros 2.0
|
/// Old-style `macro_rules` or the new macros 2.0
|
||||||
|
@ -94,8 +94,6 @@ impl DeclarativeMacroExpander {
|
||||||
def_crate: CrateId,
|
def_crate: CrateId,
|
||||||
id: AstId<ast::Macro>,
|
id: AstId<ast::Macro>,
|
||||||
) -> Arc<DeclarativeMacroExpander> {
|
) -> Arc<DeclarativeMacroExpander> {
|
||||||
let crate_data = &db.crate_graph()[def_crate];
|
|
||||||
let is_2021 = crate_data.edition >= Edition::Edition2021;
|
|
||||||
let (root, map) = crate::db::parse_with_map(db, id.file_id);
|
let (root, map) = crate::db::parse_with_map(db, id.file_id);
|
||||||
let root = root.syntax_node();
|
let root = root.syntax_node();
|
||||||
|
|
||||||
|
@ -133,6 +131,16 @@ impl DeclarativeMacroExpander {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let edition = |ctx: SyntaxContextId| {
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
if ctx.is_root() {
|
||||||
|
crate_graph[def_crate].edition
|
||||||
|
} else {
|
||||||
|
let data = db.lookup_intern_syntax_context(ctx);
|
||||||
|
// UNWRAP-SAFETY: Only the root context has no outer expansion
|
||||||
|
crate_graph[data.outer_expn.unwrap().lookup(db).def.krate].edition
|
||||||
|
}
|
||||||
|
};
|
||||||
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
|
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
|
||||||
ast::Macro::MacroRules(macro_rules) => (
|
ast::Macro::MacroRules(macro_rules) => (
|
||||||
match macro_rules.token_tree() {
|
match macro_rules.token_tree() {
|
||||||
|
@ -145,12 +153,11 @@ impl DeclarativeMacroExpander {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars)
|
mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
|
||||||
}
|
}
|
||||||
None => mbe::DeclarativeMacro::from_err(
|
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
|
||||||
mbe::ParseError::Expected("expected a token tree".into()),
|
"expected a token tree".into(),
|
||||||
is_2021,
|
)),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
transparency(¯o_rules).unwrap_or(Transparency::SemiTransparent),
|
transparency(¯o_rules).unwrap_or(Transparency::SemiTransparent),
|
||||||
),
|
),
|
||||||
|
@ -163,12 +170,11 @@ impl DeclarativeMacroExpander {
|
||||||
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
|
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
|
||||||
);
|
);
|
||||||
|
|
||||||
mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars)
|
mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
|
||||||
}
|
}
|
||||||
None => mbe::DeclarativeMacro::from_err(
|
None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected(
|
||||||
mbe::ParseError::Expected("expected a token tree".into()),
|
"expected a token tree".into(),
|
||||||
is_2021,
|
)),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
transparency(¯o_def).unwrap_or(Transparency::Opaque),
|
transparency(¯o_def).unwrap_or(Transparency::Opaque),
|
||||||
),
|
),
|
||||||
|
|
|
@ -23,7 +23,11 @@ fn benchmark_parse_macro_rules() {
|
||||||
let _pt = bench("mbe parse macro rules");
|
let _pt = bench("mbe parse macro rules");
|
||||||
rules
|
rules
|
||||||
.values()
|
.values()
|
||||||
.map(|it| DeclarativeMacro::parse_macro_rules(it, true, true).rules.len())
|
.map(|it| {
|
||||||
|
DeclarativeMacro::parse_macro_rules(it, |_| span::Edition::CURRENT, true)
|
||||||
|
.rules
|
||||||
|
.len()
|
||||||
|
})
|
||||||
.sum()
|
.sum()
|
||||||
};
|
};
|
||||||
assert_eq!(hash, 1144);
|
assert_eq!(hash, 1144);
|
||||||
|
@ -54,7 +58,9 @@ fn benchmark_expand_macro_rules() {
|
||||||
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
|
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
|
||||||
macro_rules_fixtures_tt()
|
macro_rules_fixtures_tt()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true)))
|
.map(|(id, tt)| {
|
||||||
|
(id, DeclarativeMacro::parse_macro_rules(&tt, |_| span::Edition::CURRENT, true))
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,12 @@ pub(crate) fn expand_rules(
|
||||||
rules: &[crate::Rule],
|
rules: &[crate::Rule],
|
||||||
input: &tt::Subtree<Span>,
|
input: &tt::Subtree<Span>,
|
||||||
marker: impl Fn(&mut Span) + Copy,
|
marker: impl Fn(&mut Span) + Copy,
|
||||||
is_2021: bool,
|
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
) -> ExpandResult<tt::Subtree<Span>> {
|
) -> ExpandResult<tt::Subtree<Span>> {
|
||||||
let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
|
let mut match_: Option<(matcher::Match, &crate::Rule)> = None;
|
||||||
for rule in rules {
|
for rule in rules {
|
||||||
let new_match = matcher::match_(&rule.lhs, input, is_2021);
|
let new_match = matcher::match_(&rule.lhs, input);
|
||||||
|
|
||||||
if new_match.err.is_none() {
|
if new_match.err.is_none() {
|
||||||
// If we find a rule that applies without errors, we're done.
|
// If we find a rule that applies without errors, we're done.
|
||||||
|
|
|
@ -108,8 +108,8 @@ impl Match {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matching errors are added to the `Match`.
|
/// Matching errors are added to the `Match`.
|
||||||
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>, is_2021: bool) -> Match {
|
pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree<Span>) -> Match {
|
||||||
let mut res = match_loop(pattern, input, is_2021);
|
let mut res = match_loop(pattern, input);
|
||||||
res.bound_count = count(res.bindings.bindings());
|
res.bound_count = count(res.bindings.bindings());
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
@ -362,7 +362,6 @@ fn match_loop_inner<'t>(
|
||||||
next_items: &mut Vec<MatchState<'t>>,
|
next_items: &mut Vec<MatchState<'t>>,
|
||||||
eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
||||||
error_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
error_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
||||||
is_2021: bool,
|
|
||||||
delim_span: tt::DelimSpan<Span>,
|
delim_span: tt::DelimSpan<Span>,
|
||||||
) {
|
) {
|
||||||
macro_rules! try_push {
|
macro_rules! try_push {
|
||||||
|
@ -474,7 +473,7 @@ fn match_loop_inner<'t>(
|
||||||
OpDelimited::Op(Op::Var { kind, name, .. }) => {
|
OpDelimited::Op(Op::Var { kind, name, .. }) => {
|
||||||
if let &Some(kind) = kind {
|
if let &Some(kind) = kind {
|
||||||
let mut fork = src.clone();
|
let mut fork = src.clone();
|
||||||
let match_res = match_meta_var(kind, &mut fork, is_2021, delim_span);
|
let match_res = match_meta_var(kind, &mut fork, delim_span);
|
||||||
match match_res.err {
|
match match_res.err {
|
||||||
None => {
|
None => {
|
||||||
// Some meta variables are optional (e.g. vis)
|
// Some meta variables are optional (e.g. vis)
|
||||||
|
@ -587,7 +586,7 @@ fn match_loop_inner<'t>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) -> Match {
|
fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>) -> Match {
|
||||||
let span = src.delimiter.delim_span();
|
let span = src.delimiter.delim_span();
|
||||||
let mut src = TtIter::new(src);
|
let mut src = TtIter::new(src);
|
||||||
let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
|
let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
|
||||||
|
@ -627,7 +626,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) ->
|
||||||
&mut next_items,
|
&mut next_items,
|
||||||
&mut eof_items,
|
&mut eof_items,
|
||||||
&mut error_items,
|
&mut error_items,
|
||||||
is_2021,
|
|
||||||
span,
|
span,
|
||||||
);
|
);
|
||||||
stdx::always!(cur_items.is_empty());
|
stdx::always!(cur_items.is_empty());
|
||||||
|
@ -741,7 +739,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree<Span>, is_2021: bool) ->
|
||||||
fn match_meta_var(
|
fn match_meta_var(
|
||||||
kind: MetaVarKind,
|
kind: MetaVarKind,
|
||||||
input: &mut TtIter<'_, Span>,
|
input: &mut TtIter<'_, Span>,
|
||||||
is_2021: bool,
|
|
||||||
delim_span: DelimSpan<Span>,
|
delim_span: DelimSpan<Span>,
|
||||||
) -> ExpandResult<Option<Fragment>> {
|
) -> ExpandResult<Option<Fragment>> {
|
||||||
let fragment = match kind {
|
let fragment = match kind {
|
||||||
|
@ -751,8 +748,7 @@ fn match_meta_var(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
|
MetaVarKind::Ty => parser::PrefixEntryPoint::Ty,
|
||||||
MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop,
|
MetaVarKind::Pat => parser::PrefixEntryPoint::PatTop,
|
||||||
MetaVarKind::Pat => parser::PrefixEntryPoint::Pat,
|
|
||||||
MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
|
MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat,
|
||||||
MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
|
MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt,
|
||||||
MetaVarKind::Block => parser::PrefixEntryPoint::Block,
|
MetaVarKind::Block => parser::PrefixEntryPoint::Block,
|
||||||
|
|
|
@ -17,7 +17,7 @@ mod tt_iter;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod benchmark;
|
mod benchmark;
|
||||||
|
|
||||||
use span::Span;
|
use span::{Edition, Span, SyntaxContextId};
|
||||||
use stdx::impl_from;
|
use stdx::impl_from;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -129,9 +129,6 @@ impl fmt::Display for CountError {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct DeclarativeMacro {
|
pub struct DeclarativeMacro {
|
||||||
rules: Box<[Rule]>,
|
rules: Box<[Rule]>,
|
||||||
// This is used for correctly determining the behavior of the pat fragment
|
|
||||||
// FIXME: This should be tracked by hygiene of the fragment identifier!
|
|
||||||
is_2021: bool,
|
|
||||||
err: Option<Box<ParseError>>,
|
err: Option<Box<ParseError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,14 +139,14 @@ struct Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeclarativeMacro {
|
impl DeclarativeMacro {
|
||||||
pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro {
|
pub fn from_err(err: ParseError) -> DeclarativeMacro {
|
||||||
DeclarativeMacro { rules: Box::default(), is_2021, err: Some(Box::new(err)) }
|
DeclarativeMacro { rules: Box::default(), err: Some(Box::new(err)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The old, `macro_rules! m {}` flavor.
|
/// The old, `macro_rules! m {}` flavor.
|
||||||
pub fn parse_macro_rules(
|
pub fn parse_macro_rules(
|
||||||
tt: &tt::Subtree<Span>,
|
tt: &tt::Subtree<Span>,
|
||||||
is_2021: bool,
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
|
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
) -> DeclarativeMacro {
|
) -> DeclarativeMacro {
|
||||||
|
@ -161,7 +158,7 @@ impl DeclarativeMacro {
|
||||||
let mut err = None;
|
let mut err = None;
|
||||||
|
|
||||||
while src.len() > 0 {
|
while src.len() > 0 {
|
||||||
let rule = match Rule::parse(&mut src, true, new_meta_vars) {
|
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
err = Some(Box::new(e));
|
err = Some(Box::new(e));
|
||||||
|
@ -184,13 +181,13 @@ impl DeclarativeMacro {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
|
DeclarativeMacro { rules: rules.into_boxed_slice(), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The new, unstable `macro m {}` flavor.
|
/// The new, unstable `macro m {}` flavor.
|
||||||
pub fn parse_macro2(
|
pub fn parse_macro2(
|
||||||
tt: &tt::Subtree<Span>,
|
tt: &tt::Subtree<Span>,
|
||||||
is_2021: bool,
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
|
// FIXME: Remove this once we drop support for rust 1.76 (defaults to true then)
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
) -> DeclarativeMacro {
|
) -> DeclarativeMacro {
|
||||||
|
@ -201,7 +198,7 @@ impl DeclarativeMacro {
|
||||||
if tt::DelimiterKind::Brace == tt.delimiter.kind {
|
if tt::DelimiterKind::Brace == tt.delimiter.kind {
|
||||||
cov_mark::hit!(parse_macro_def_rules);
|
cov_mark::hit!(parse_macro_def_rules);
|
||||||
while src.len() > 0 {
|
while src.len() > 0 {
|
||||||
let rule = match Rule::parse(&mut src, true, new_meta_vars) {
|
let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) {
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
err = Some(Box::new(e));
|
err = Some(Box::new(e));
|
||||||
|
@ -220,7 +217,7 @@ impl DeclarativeMacro {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cov_mark::hit!(parse_macro_def_simple);
|
cov_mark::hit!(parse_macro_def_simple);
|
||||||
match Rule::parse(&mut src, false, new_meta_vars) {
|
match Rule::parse(edition, &mut src, false, new_meta_vars) {
|
||||||
Ok(rule) => {
|
Ok(rule) => {
|
||||||
if src.len() != 0 {
|
if src.len() != 0 {
|
||||||
err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
|
err = Some(Box::new(ParseError::expected("remaining tokens in macro def")));
|
||||||
|
@ -240,7 +237,7 @@ impl DeclarativeMacro {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err }
|
DeclarativeMacro { rules: rules.into_boxed_slice(), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err(&self) -> Option<&ParseError> {
|
pub fn err(&self) -> Option<&ParseError> {
|
||||||
|
@ -254,12 +251,13 @@ impl DeclarativeMacro {
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
call_site: Span,
|
call_site: Span,
|
||||||
) -> ExpandResult<tt::Subtree<Span>> {
|
) -> ExpandResult<tt::Subtree<Span>> {
|
||||||
expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site)
|
expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rule {
|
impl Rule {
|
||||||
fn parse(
|
fn parse(
|
||||||
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
src: &mut TtIter<'_, Span>,
|
src: &mut TtIter<'_, Span>,
|
||||||
expect_arrow: bool,
|
expect_arrow: bool,
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
|
@ -271,8 +269,8 @@ impl Rule {
|
||||||
}
|
}
|
||||||
let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
|
let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?;
|
||||||
|
|
||||||
let lhs = MetaTemplate::parse_pattern(lhs)?;
|
let lhs = MetaTemplate::parse_pattern(edition, lhs)?;
|
||||||
let rhs = MetaTemplate::parse_template(rhs, new_meta_vars)?;
|
let rhs = MetaTemplate::parse_template(edition, rhs, new_meta_vars)?;
|
||||||
|
|
||||||
Ok(crate::Rule { lhs, rhs })
|
Ok(crate::Rule { lhs, rhs })
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! trees.
|
//! trees.
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use span::Span;
|
use span::{Edition, Span, SyntaxContextId};
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{tt_iter::TtIter, ParseError};
|
use crate::{tt_iter::TtIter, ParseError};
|
||||||
|
@ -24,27 +24,36 @@ use crate::{tt_iter::TtIter, ParseError};
|
||||||
pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
|
pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
|
||||||
|
|
||||||
impl MetaTemplate {
|
impl MetaTemplate {
|
||||||
pub(crate) fn parse_pattern(pattern: &tt::Subtree<Span>) -> Result<Self, ParseError> {
|
pub(crate) fn parse_pattern(
|
||||||
MetaTemplate::parse(pattern, Mode::Pattern, false)
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
|
pattern: &tt::Subtree<Span>,
|
||||||
|
) -> Result<Self, ParseError> {
|
||||||
|
MetaTemplate::parse(edition, pattern, Mode::Pattern, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_template(
|
pub(crate) fn parse_template(
|
||||||
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
template: &tt::Subtree<Span>,
|
template: &tt::Subtree<Span>,
|
||||||
new_meta_vars: bool,
|
new_meta_vars: bool,
|
||||||
) -> Result<Self, ParseError> {
|
) -> Result<Self, ParseError> {
|
||||||
MetaTemplate::parse(template, Mode::Template, new_meta_vars)
|
MetaTemplate::parse(edition, template, Mode::Template, new_meta_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
|
pub(crate) fn iter(&self) -> impl Iterator<Item = &Op> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(tt: &tt::Subtree<Span>, mode: Mode, new_meta_vars: bool) -> Result<Self, ParseError> {
|
fn parse(
|
||||||
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
|
tt: &tt::Subtree<Span>,
|
||||||
|
mode: Mode,
|
||||||
|
new_meta_vars: bool,
|
||||||
|
) -> Result<Self, ParseError> {
|
||||||
let mut src = TtIter::new(tt);
|
let mut src = TtIter::new(tt);
|
||||||
|
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
while let Some(first) = src.peek_n(0) {
|
while let Some(first) = src.peek_n(0) {
|
||||||
let op = next_op(first, &mut src, mode, new_meta_vars)?;
|
let op = next_op(edition, first, &mut src, mode, new_meta_vars)?;
|
||||||
res.push(op);
|
res.push(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +154,7 @@ enum Mode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_op(
|
fn next_op(
|
||||||
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
first_peeked: &tt::TokenTree<Span>,
|
first_peeked: &tt::TokenTree<Span>,
|
||||||
src: &mut TtIter<'_, Span>,
|
src: &mut TtIter<'_, Span>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
|
@ -162,7 +172,7 @@ fn next_op(
|
||||||
tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind {
|
tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind {
|
||||||
tt::DelimiterKind::Parenthesis => {
|
tt::DelimiterKind::Parenthesis => {
|
||||||
let (separator, kind) = parse_repeat(src)?;
|
let (separator, kind) = parse_repeat(src)?;
|
||||||
let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
|
let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?;
|
||||||
Op::Repeat { tokens, separator, kind }
|
Op::Repeat { tokens, separator, kind }
|
||||||
}
|
}
|
||||||
tt::DelimiterKind::Brace => match mode {
|
tt::DelimiterKind::Brace => match mode {
|
||||||
|
@ -189,13 +199,13 @@ fn next_op(
|
||||||
Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span })
|
Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span })
|
||||||
}
|
}
|
||||||
tt::Leaf::Ident(ident) => {
|
tt::Leaf::Ident(ident) => {
|
||||||
let kind = eat_fragment_kind(src, mode)?;
|
let kind = eat_fragment_kind(edition, src, mode)?;
|
||||||
let name = ident.text.clone();
|
let name = ident.text.clone();
|
||||||
let id = ident.span;
|
let id = ident.span;
|
||||||
Op::Var { name, kind, id }
|
Op::Var { name, kind, id }
|
||||||
}
|
}
|
||||||
tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
|
tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
|
||||||
let kind = eat_fragment_kind(src, mode)?;
|
let kind = eat_fragment_kind(edition, src, mode)?;
|
||||||
let name = lit.text.clone();
|
let name = lit.text.clone();
|
||||||
let id = lit.span;
|
let id = lit.span;
|
||||||
Op::Var { name, kind, id }
|
Op::Var { name, kind, id }
|
||||||
|
@ -233,7 +243,7 @@ fn next_op(
|
||||||
|
|
||||||
tt::TokenTree::Subtree(subtree) => {
|
tt::TokenTree::Subtree(subtree) => {
|
||||||
src.next().expect("first token already peeked");
|
src.next().expect("first token already peeked");
|
||||||
let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?;
|
let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?;
|
||||||
Op::Subtree { tokens, delimiter: subtree.delimiter }
|
Op::Subtree { tokens, delimiter: subtree.delimiter }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -241,6 +251,7 @@ fn next_op(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_fragment_kind(
|
fn eat_fragment_kind(
|
||||||
|
edition: impl Copy + Fn(SyntaxContextId) -> Edition,
|
||||||
src: &mut TtIter<'_, Span>,
|
src: &mut TtIter<'_, Span>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
) -> Result<Option<MetaVarKind>, ParseError> {
|
) -> Result<Option<MetaVarKind>, ParseError> {
|
||||||
|
@ -252,7 +263,10 @@ fn eat_fragment_kind(
|
||||||
let kind = match ident.text.as_str() {
|
let kind = match ident.text.as_str() {
|
||||||
"path" => MetaVarKind::Path,
|
"path" => MetaVarKind::Path,
|
||||||
"ty" => MetaVarKind::Ty,
|
"ty" => MetaVarKind::Ty,
|
||||||
"pat" => MetaVarKind::Pat,
|
"pat" => match edition(ident.span.ctx) {
|
||||||
|
Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam,
|
||||||
|
Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat,
|
||||||
|
},
|
||||||
"pat_param" => MetaVarKind::PatParam,
|
"pat_param" => MetaVarKind::PatParam,
|
||||||
"stmt" => MetaVarKind::Stmt,
|
"stmt" => MetaVarKind::Stmt,
|
||||||
"block" => MetaVarKind::Block,
|
"block" => MetaVarKind::Block,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue