From 79ec6878877f0fd9246d67d3cd4f8cc2d1200150 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 17 Jul 2026 11:08:07 +0800 Subject: refactor: rename `mingling_picker` to `arg_picker` --- mingling_picker_macros/src/internal_repeat.rs | 315 -------------------------- 1 file changed, 315 deletions(-) delete mode 100644 mingling_picker_macros/src/internal_repeat.rs (limited to 'mingling_picker_macros/src/internal_repeat.rs') diff --git a/mingling_picker_macros/src/internal_repeat.rs b/mingling_picker_macros/src/internal_repeat.rs deleted file mode 100644 index 4b2242b..0000000 --- a/mingling_picker_macros/src/internal_repeat.rs +++ /dev/null @@ -1,315 +0,0 @@ -use proc_macro::{Delimiter, Group, Ident, Literal, TokenStream, TokenTree}; - -pub(crate) fn internal_repeat(input: TokenStream) -> TokenStream { - let tokens: Vec = input.into_iter().collect(); - let (range_start, range_end, body_start) = parse_range(&tokens); - - let mut body: Vec = tokens[body_start..].to_vec(); - if body.len() == 1 - && let TokenTree::Group(g) = &body[0] - && g.delimiter() == Delimiter::Brace - { - body = g.stream().into_iter().collect(); - } - - let mut result = Vec::new(); - for i in range_start..=range_end { - result.extend(expand_body(&body, i, range_start, range_end)); - } - result.into_iter().collect() -} - -/// Parse `start .. end =>` or `start ..= end =>` or `count =>` (backward compat). -/// Returns `(start, end_inclusive, body_start_index)`. -fn parse_range(tokens: &[TokenTree]) -> (usize, usize, usize) { - // Find => separator - let arrow_pos = tokens.windows(2).position(|w| { - matches!(&w[0], TokenTree::Punct(p) if p.as_char() == '=') - && matches!(&w[1], TokenTree::Punct(p) if p.as_char() == '>') - }); - - let (arrow_pos, body_start) = match arrow_pos { - Some(p) => (p, p + 2), - None => return (1, 12, 0), // fallback - }; - - let before: Vec<&TokenTree> = tokens[..arrow_pos].iter().collect(); - - // Try to find `..` or `..=` pattern - // `..` is two Punct('.') tokens - let dotdot = before.windows(2).position(|w| { - matches!(w[0], TokenTree::Punct(p) if p.as_char() == '.') - && matches!(w[1], TokenTree::Punct(p) if p.as_char() == '.') - }); - - if let Some(dd) = dotdot { - // Start value: tokens before `..` - let start = parse_usize_tokens(&before[..dd]); - let after_dd = &before[dd + 2..]; - - // Check for `..=` (inclusive range) - let (inclusive, end_tokens) = if after_dd - .first() - .is_some_and(|t| matches!(t, TokenTree::Punct(p) if p.as_char() == '=')) - { - (true, &after_dd[1..]) - } else { - (false, after_dd) - }; - - let end = parse_usize_tokens(end_tokens); - - if inclusive { - (start, end, body_start) - } else { - // Exclusive end: if end >= start, iterate start..end, so end_inclusive = end - 1 - if end > start { - (start, end - 1, body_start) - } else { - (1, 12, body_start) // fallback - } - } - } else { - // No `..` found — fallback to simple count - let count = parse_usize_tokens(&before); - (1, count, body_start) - } -} - -/// Parse a sequence of tokens as a single usize value. -fn parse_usize_tokens(tokens: &[&TokenTree]) -> usize { - let s: String = tokens - .iter() - .map(|t| match t { - TokenTree::Literal(l) => l.to_string(), - TokenTree::Ident(id) => id.to_string(), - _ => String::new(), - }) - .collect::>() - .join("") - .replace(' ', ""); - - s.parse().unwrap_or(12) -} - -/// Walk tokens, replacing: -/// `$` → current -/// `^$` → max -/// `$^` → min -/// `$+` → current + 1 (clamped) -/// `$-` → current - 1 (clamped) -/// `ident$` → ident{current} -/// and expanding `( … )+` / `( … ,)+` / `( … ;)+` groups. -fn expand_body(tokens: &[TokenTree], current: usize, min: usize, max: usize) -> Vec { - let mut out = Vec::new(); - let mut i = 0; - while i < tokens.len() { - // Check for a parenthesized repetition group: ( ... ) sep? + - if let Some(exp) = try_expand_paren_group(tokens, i, current, min, max) { - let (items, consumed) = exp; - out.extend(items); - i += consumed; - continue; - } - - // `^$` — max value - if let TokenTree::Punct(p) = &tokens[i] - && p.as_char() == '^' - && i + 1 < tokens.len() - && let TokenTree::Punct(p2) = &tokens[i + 1] - && p2.as_char() == '$' - { - out.push(TokenTree::Literal(Literal::usize_suffixed(max))); - i += 2; - continue; - } - - // `ident$` / `ident$+` / `ident$-` / `ident$^` - // → {ident}{current} / {ident}{current+1} / {ident}{current-1} / {ident}{min} - if let TokenTree::Ident(id) = &tokens[i] { - if i + 1 < tokens.len() - && let TokenTree::Punct(p) = &tokens[i + 1] - && p.as_char() == '$' - { - // Check for ident$+ / ident$- / ident$^ - if i + 2 < tokens.len() { - match &tokens[i + 2] { - TokenTree::Punct(p2) if p2.as_char() == '+' => { - // ident$+ → {ident}{current+1} - let name = format!("{}{}", id, current + 1); - out.push(TokenTree::Ident(Ident::new(&name, id.span()))); - i += 3; - continue; - } - TokenTree::Punct(p2) if p2.as_char() == '-' => { - // ident$- → {ident}{current-1} - let val = current.saturating_sub(1); - let name = format!("{}{}", id, val); - out.push(TokenTree::Ident(Ident::new(&name, id.span()))); - i += 3; - continue; - } - TokenTree::Punct(p2) if p2.as_char() == '^' => { - let name = format!("{}{}", id, min); - out.push(TokenTree::Ident(Ident::new(&name, id.span()))); - i += 3; - continue; - } - _ => {} - } - } - // ident$ alone → {ident}{current} - let name = format!("{}{}", id, current); - out.push(TokenTree::Ident(Ident::new(&name, id.span()))); - i += 2; - continue; - } - out.push(tokens[i].clone()); - i += 1; - continue; - } - - match &tokens[i] { - TokenTree::Punct(p) if p.as_char() == '$' => { - // lookahead for $^, $+, $- - if i + 1 < tokens.len() { - match &tokens[i + 1] { - TokenTree::Punct(p2) if p2.as_char() == '^' => { - // $^ → min - out.push(TokenTree::Literal(Literal::usize_suffixed(min))); - i += 2; - continue; - } - TokenTree::Punct(p2) if p2.as_char() == '+' => { - // $+ → current + 1 - out.push(TokenTree::Literal(Literal::usize_suffixed(current + 1))); - i += 2; - continue; - } - TokenTree::Punct(p2) if p2.as_char() == '-' => { - // $- → current - 1 - let val = current.saturating_sub(1); - out.push(TokenTree::Literal(Literal::usize_suffixed(val))); - i += 2; - continue; - } - _ => {} - } - } - // `$` alone → current - out.push(TokenTree::Literal(Literal::usize_suffixed(current))); - i += 1; - continue; - } - TokenTree::Group(g) => { - let inner = expand_body_vec(&g.stream(), current, min, max); - out.push(TokenTree::Group(Group::new( - g.delimiter(), - inner.into_iter().collect(), - ))); - } - other => out.push(other.clone()), - } - i += 1; - } - out -} - -fn expand_body_vec(stream: &TokenStream, current: usize, min: usize, max: usize) -> Vec { - let v: Vec = stream.clone().into_iter().collect(); - expand_body(&v, current, min, max) -} - -/// Try to expand a repetition group. -/// -/// New syntax (repetition marker `+` is the LAST token INSIDE the parens): -/// - `(group,+)` — repeat `*` times (current), `,` is the separator -/// - `(group,+)` — repeat `*` times, `,` is the separator -/// - `(group,+)` — repeat `*` times, `;` is the separator -/// - `(group +)` — repeat `*` times, no separator -/// - `(group,+)+` — repeat `*+1` times (with separator) -/// - `(group,+)--` — repeat `*-1` times (with separator) [not yet used] -/// -/// The `*` is the current counter value. An optional `+` or `-` immediately -/// after the closing paren shifts the repeat count up or down by one. -fn try_expand_paren_group( - tokens: &[TokenTree], - i: usize, - current: usize, - _min: usize, - _max: usize, -) -> Option<(Vec, usize)> { - let group = match tokens.get(i)? { - TokenTree::Group(g) if g.delimiter() == Delimiter::Parenthesis => g, - _ => return None, - }; - - let stream: Vec = group.stream().into_iter().collect(); - - // Repetition syntax: the LAST token inside the parens MUST be `+`. - // `(content,+)` — repeat * times, `,` separator - // `(content;+)` — repeat * times, `;` separator - // `(content,+)` — repeat * times, no separator - // `(content,+)+` — repeat *+1 times - // `(content,+)-` — repeat *-1 times - // An optional `+` / `-` right after `)` shifts the count by ±1. - // - // Any `+` tokens inside `content` are treated as regular Rust syntax - // (trait bounds, etc.) — the repetition marker is ONLY the final `+`. - - let last_is_plus = stream - .last() - .is_some_and(|t| matches!(t, TokenTree::Punct(p) if p.as_char() == '+')); - if !last_is_plus { - return None; - } - - // Determine separator and inner content. - let (inner, sep_str): (Vec, &str) = { - if stream.len() >= 2 { - let sep_idx = stream.len() - 2; - match &stream[sep_idx] { - TokenTree::Punct(p) if p.as_char() == ',' => { - // (...,content,+) — inner is everything before the last `,` - let content: Vec = stream[..sep_idx].into(); - (content, ",") - } - TokenTree::Punct(p) if p.as_char() == ';' => { - let content: Vec = stream[..sep_idx].into(); - (content, ";") - } - _ => { - // (content+) — no separator, the `+` is the only special token - let content: Vec = stream[..stream.len() - 1].into(); - (content, "") - } - } - } else { - // (+) — bare repetition marker, empty content - (vec![], "") - } - }; - - // Handle modifier after `)` - let rest = &tokens[i + 1..]; - let modifier: isize = match rest.first() { - Some(TokenTree::Punct(p)) if p.as_char() == '+' => 1, - Some(TokenTree::Punct(p)) if p.as_char() == '-' => -1, - _ => 0, - }; - let consumed = if modifier != 0 { 2 } else { 1 }; - let repeat_count = (current as isize + modifier) as usize; - - let mut out = Vec::new(); - for n in 1..=repeat_count { - if n > 1 && !sep_str.is_empty() { - out.push(TokenTree::Punct(proc_macro::Punct::new( - sep_str.chars().next().unwrap(), - proc_macro::Spacing::Alone, - ))); - } - out.extend(expand_body(&inner, n, 1, repeat_count)); - } - - Some((out, consumed)) -} -- cgit