1
Fork 0

Allow concat in repetitions

This commit is contained in:
Caio 2024-07-19 21:00:46 -03:00
parent 52f3c71c8d
commit b8d4e4d1b3
4 changed files with 90 additions and 45 deletions

View file

@ -352,10 +352,10 @@ fn check_occurrences(
check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name); check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name);
} }
TokenTree::MetaVarExpr(dl, ref mve) => { TokenTree::MetaVarExpr(dl, ref mve) => {
let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else { mve.for_each_metavar((), |_, ident| {
return; let name = MacroRulesNormalizedIdent::new(*ident);
}; check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name);
check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name); });
} }
TokenTree::Delimited(.., ref del) => { TokenTree::Delimited(.., ref del) => {
check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar); check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar);

View file

@ -111,10 +111,18 @@ impl MetaVarExpr {
Ok(rslt) Ok(rslt)
} }
pub(crate) fn ident(&self) -> Option<Ident> { pub(crate) fn for_each_metavar<A>(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A {
match *self { match self {
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), MetaVarExpr::Concat(elems) => {
MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, for elem in elems {
if let MetaVarExprConcatElem::Var(ident) = elem {
aux = cb(aux, ident)
}
}
aux
}
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident),
MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux,
} }
} }
} }

View file

@ -557,17 +557,13 @@ fn lockstep_iter_size(
} }
} }
TokenTree::MetaVarExpr(_, expr) => { TokenTree::MetaVarExpr(_, expr) => {
let default_rslt = LockstepIterSize::Unconstrained; expr.for_each_metavar(LockstepIterSize::Unconstrained, |lis, ident| {
let Some(ident) = expr.ident() else { lis.with(lockstep_iter_size(
return default_rslt; &TokenTree::MetaVar(ident.span, *ident),
}; interpolations,
let name = MacroRulesNormalizedIdent::new(ident); repeats,
match lookup_cur_matched(name, interpolations, repeats) { ))
Some(MatchedSeq(ads)) => { })
default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
}
_ => default_rslt,
}
} }
TokenTree::Token(..) => LockstepIterSize::Unconstrained, TokenTree::Token(..) => LockstepIterSize::Unconstrained,
} }
@ -695,7 +691,23 @@ fn transcribe_metavar_expr<'a>(
let symbol = match element { let symbol = match element {
MetaVarExprConcatElem::Ident(elem) => elem.name, MetaVarExprConcatElem::Ident(elem) => elem.name,
MetaVarExprConcatElem::Literal(elem) => *elem, MetaVarExprConcatElem::Literal(elem) => *elem,
MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?, MetaVarExprConcatElem::Var(ident) => {
match matched_from_ident(dcx, *ident, interp)? {
NamedMatch::MatchedSeq(named_matches) => {
let curr_idx = repeats.last().unwrap().0;
match &named_matches[curr_idx] {
// FIXME(c410-f3r) Nested repetitions are unimplemented
MatchedSeq(_) => unimplemented!(),
MatchedSingle(pnr) => {
extract_symbol_from_pnr(dcx, pnr, ident.span)?
}
}
}
NamedMatch::MatchedSingle(pnr) => {
extract_symbol_from_pnr(dcx, pnr, ident.span)?
}
}
}
}; };
concatenated.push_str(symbol.as_str()); concatenated.push_str(symbol.as_str());
} }
@ -752,41 +764,48 @@ fn transcribe_metavar_expr<'a>(
} }
/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal. /// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
fn extract_var_symbol<'a>( fn extract_symbol_from_pnr<'a>(
dcx: DiagCtxtHandle<'a>, dcx: DiagCtxtHandle<'a>,
ident: Ident, pnr: &ParseNtResult,
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, span_err: Span,
) -> PResult<'a, Symbol> { ) -> PResult<'a, Symbol> {
if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { match pnr {
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { ParseNtResult::Ident(nt_ident, is_raw) => {
if let IdentIsRaw::Yes = is_raw { if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
} }
return Ok(nt_ident.name); return Ok(nt_ident.name);
} }
ParseNtResult::Tt(TokenTree::Token(
if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr { Token { kind: TokenKind::Ident(symbol, is_raw), .. },
if let TokenKind::Ident(symbol, is_raw) = kind { _,
if let IdentIsRaw::Yes = is_raw { )) => {
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); if let IdentIsRaw::Yes = is_raw {
} return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR));
return Ok(*symbol);
}
if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
return Ok(*symbol);
} }
return Ok(*symbol);
} }
ParseNtResult::Tt(TokenTree::Token(
if let ParseNtResult::Nt(nt) = pnr Token {
&& let Nonterminal::NtLiteral(expr) = &**nt kind: TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }),
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind ..
},
_,
)) => {
return Ok(*symbol);
}
ParseNtResult::Nt(nt)
if let Nonterminal::NtLiteral(expr) = &**nt
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) =
&expr.kind =>
{ {
return Ok(*symbol); return Ok(*symbol);
} }
_ => Err(dcx
.struct_err(
"metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`",
)
.with_note("currently only string literals are supported")
.with_span(span_err)),
} }
Err(dcx
.struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
.with_note("currently only string literals are supported")
.with_span(ident.span))
} }

View file

@ -0,0 +1,18 @@
//@ run-pass
#![feature(macro_metavar_expr_concat)]
macro_rules! one_rep {
( $($a:ident)* ) => {
$(
const ${concat($a, Z)}: i32 = 3;
)*
};
}
fn main() {
one_rep!(A B C);
assert_eq!(AZ, 3);
assert_eq!(BZ, 3);
assert_eq!(CZ, 3);
}