Skip to main content

oxilean_parse/macro_parser/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use crate::error_impl::ParseError;
7use crate::tokens::{Span, Token, TokenKind};
8use std::collections::HashMap;
9
10/// A macro template variable.
11#[allow(dead_code)]
12#[allow(missing_docs)]
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct MacroVarExt {
15    /// Variable name
16    pub name: String,
17    /// Whether this is a repetition variable
18    pub is_rep: bool,
19}
20impl MacroVarExt {
21    /// Create a simple macro variable.
22    #[allow(dead_code)]
23    pub fn simple(name: &str) -> Self {
24        MacroVarExt {
25            name: name.to_string(),
26            is_rep: false,
27        }
28    }
29    /// Create a repetition macro variable.
30    #[allow(dead_code)]
31    pub fn rep(name: &str) -> Self {
32        MacroVarExt {
33            name: name.to_string(),
34            is_rep: true,
35        }
36    }
37}
38/// A macro library with named groups.
39#[allow(dead_code)]
40#[allow(missing_docs)]
41pub struct MacroLibrary {
42    /// Groups of macros
43    pub groups: std::collections::HashMap<String, Vec<MacroDefinitionExt>>,
44}
45impl MacroLibrary {
46    /// Create a new empty library.
47    #[allow(dead_code)]
48    pub fn new() -> Self {
49        MacroLibrary {
50            groups: std::collections::HashMap::new(),
51        }
52    }
53    /// Add a macro to a group.
54    #[allow(dead_code)]
55    pub fn add_to_group(&mut self, group: &str, def: MacroDefinitionExt) {
56        self.groups.entry(group.to_string()).or_default().push(def);
57    }
58    /// Returns all macros in a group.
59    #[allow(dead_code)]
60    pub fn group(&self, name: &str) -> &[MacroDefinitionExt] {
61        self.groups.get(name).map(|v| v.as_slice()).unwrap_or(&[])
62    }
63    /// Total number of macros.
64    #[allow(dead_code)]
65    pub fn total_macros(&self) -> usize {
66        self.groups.values().map(|v| v.len()).sum()
67    }
68}
69/// An item in a `syntax` parser specification.
70#[derive(Debug, Clone, PartialEq)]
71pub enum SyntaxItem {
72    /// A specific token (keyword, punctuation, etc.).
73    Token(TokenKind),
74    /// A syntactic category placeholder (e.g. `term`, `ident`).
75    Category(String),
76    /// An optional sub-item.
77    Optional(Box<SyntaxItem>),
78    /// Zero-or-more repetition.
79    Many(Box<SyntaxItem>),
80    /// A grouped sequence.
81    Group(Vec<SyntaxItem>),
82}
83/// A macro substitution record.
84#[allow(dead_code)]
85#[allow(missing_docs)]
86#[derive(Debug, Clone)]
87pub struct MacroSubst {
88    /// Variable name
89    pub var: String,
90    /// Substituted value
91    pub value: String,
92}
93impl MacroSubst {
94    /// Create a new substitution.
95    #[allow(dead_code)]
96    pub fn new(var: &str, value: &str) -> Self {
97        MacroSubst {
98            var: var.to_string(),
99            value: value.to_string(),
100        }
101    }
102}
103/// A complete macro definition, potentially with multiple rules.
104#[derive(Debug, Clone)]
105pub struct MacroDef {
106    /// The macro name.
107    pub name: String,
108    /// Ordered list of rewrite rules (first match wins).
109    pub rules: Vec<MacroRule>,
110    /// Optional documentation string.
111    pub doc: Option<String>,
112    /// Hygiene information for the definition site.
113    pub hygiene: HygieneInfo,
114}
115impl MacroDef {
116    /// Create a new macro definition.
117    pub fn new(name: String, rules: Vec<MacroRule>, hygiene: HygieneInfo) -> Self {
118        Self {
119            name,
120            rules,
121            doc: None,
122            hygiene,
123        }
124    }
125    /// Attach documentation.
126    pub fn with_doc(mut self, doc: String) -> Self {
127        self.doc = Some(doc);
128        self
129    }
130    /// Number of rules.
131    pub fn rule_count(&self) -> usize {
132        self.rules.len()
133    }
134}
135/// A macro expansion result: either a string or an error.
136#[allow(dead_code)]
137#[allow(missing_docs)]
138#[derive(Debug, Clone)]
139pub enum MacroExpansionResult {
140    /// Successful expansion
141    Ok(String),
142    /// Failed expansion
143    Err(MacroExpansionError),
144}
145impl MacroExpansionResult {
146    /// Returns true if expansion succeeded.
147    #[allow(dead_code)]
148    pub fn is_ok(&self) -> bool {
149        matches!(self, MacroExpansionResult::Ok(_))
150    }
151    /// Unwrap the success value.
152    #[allow(dead_code)]
153    pub fn unwrap(self) -> String {
154        match self {
155            MacroExpansionResult::Ok(s) => s,
156            MacroExpansionResult::Err(e) => {
157                panic!("macro expansion error: {}", e.message)
158            }
159        }
160    }
161    /// Unwrap or return a default.
162    #[allow(dead_code)]
163    pub fn unwrap_or(self, default: &str) -> String {
164        match self {
165            MacroExpansionResult::Ok(s) => s,
166            MacroExpansionResult::Err(_) => default.to_string(),
167        }
168    }
169}
170/// A macro pattern matcher that checks if a token sequence matches a macro pattern.
171#[allow(dead_code)]
172#[allow(missing_docs)]
173pub struct MacroMatcher {
174    /// The pattern (list of literals and holes)
175    pub pattern: Vec<MacroVarExt>,
176}
177impl MacroMatcher {
178    /// Create a new matcher from a space-separated pattern string.
179    #[allow(dead_code)]
180    #[allow(clippy::should_implement_trait)]
181    pub fn from_str(s: &str) -> Self {
182        MacroMatcher {
183            pattern: s
184                .split_whitespace()
185                .map(|tok| {
186                    if let Some(name) = tok.strip_prefix('$') {
187                        MacroVarExt::simple(name)
188                    } else {
189                        MacroVarExt {
190                            name: format!("__lit_{}", tok),
191                            is_rep: false,
192                        }
193                    }
194                })
195                .collect(),
196        }
197    }
198    /// Returns the number of holes.
199    #[allow(dead_code)]
200    pub fn hole_count(&self) -> usize {
201        self.pattern
202            .iter()
203            .filter(|v| !v.name.starts_with("__lit_"))
204            .count()
205    }
206    /// Returns the number of literal tokens.
207    #[allow(dead_code)]
208    pub fn literal_count(&self) -> usize {
209        self.pattern
210            .iter()
211            .filter(|v| v.name.starts_with("__lit_"))
212            .count()
213    }
214}
215/// An error that occurred during macro expansion.
216#[allow(dead_code)]
217#[allow(missing_docs)]
218#[derive(Debug, Clone)]
219pub struct MacroExpansionErrorExt2 {
220    /// Error message
221    pub message: String,
222    /// Macro name
223    pub macro_name: String,
224    /// Expansion depth at which error occurred
225    pub depth: usize,
226}
227impl MacroExpansionErrorExt2 {
228    /// Create a new expansion error.
229    #[allow(dead_code)]
230    pub fn new(macro_name: &str, message: &str, depth: usize) -> Self {
231        MacroExpansionErrorExt2 {
232            message: message.to_string(),
233            macro_name: macro_name.to_string(),
234            depth,
235        }
236    }
237    /// Format the error as a string.
238    #[allow(dead_code)]
239    pub fn format(&self) -> String {
240        format!(
241            "macro '{}' at depth {}: {}",
242            self.macro_name, self.depth, self.message
243        )
244    }
245}
246/// A macro expansion trace for debugging.
247#[allow(dead_code)]
248#[allow(missing_docs)]
249#[derive(Debug, Default)]
250pub struct MacroExpansionTraceExt {
251    /// Steps in the trace
252    pub steps: Vec<String>,
253}
254impl MacroExpansionTraceExt {
255    /// Create a new empty trace.
256    #[allow(dead_code)]
257    pub fn new() -> Self {
258        MacroExpansionTraceExt { steps: Vec::new() }
259    }
260    /// Record an expansion step.
261    #[allow(dead_code)]
262    pub fn record(&mut self, step: &str) {
263        self.steps.push(step.to_string());
264    }
265    /// Format the trace as a string.
266    #[allow(dead_code)]
267    pub fn format(&self) -> String {
268        self.steps
269            .iter()
270            .enumerate()
271            .map(|(i, s)| format!("{}: {}", i, s))
272            .collect::<Vec<_>>()
273            .join("\n")
274    }
275}
276/// A macro error during expansion.
277#[allow(dead_code)]
278#[allow(missing_docs)]
279#[derive(Debug, Clone)]
280pub struct MacroExpansionError {
281    /// The macro that failed
282    pub macro_name: String,
283    /// The error message
284    pub message: String,
285    /// Expansion depth at time of error
286    pub depth: usize,
287}
288impl MacroExpansionError {
289    /// Create a new expansion error.
290    #[allow(dead_code)]
291    pub fn new(macro_name: &str, message: &str, depth: usize) -> Self {
292        MacroExpansionError {
293            macro_name: macro_name.to_string(),
294            message: message.to_string(),
295            depth,
296        }
297    }
298    /// Format the error.
299    #[allow(dead_code)]
300    pub fn format(&self) -> String {
301        format!(
302            "macro error in '{}' at depth {}: {}",
303            self.macro_name, self.depth, self.message
304        )
305    }
306}
307/// Kinds of macro errors.
308#[derive(Debug, Clone, PartialEq, Eq)]
309pub enum MacroErrorKind {
310    /// The named macro is not registered.
311    UnknownMacro,
312    /// No rule pattern matched the input.
313    PatternMismatch,
314    /// A hygiene violation was detected.
315    HygieneViolation,
316    /// Multiple rules matched ambiguously.
317    AmbiguousMatch,
318    /// An error occurred during template expansion.
319    ExpansionError,
320}
321/// A depth-limited macro expander.
322#[allow(dead_code)]
323#[allow(missing_docs)]
324pub struct DepthLimitedExpanderExt2 {
325    /// Maximum expansion depth
326    pub max_depth: usize,
327    /// Current depth
328    pub current_depth: usize,
329}
330impl DepthLimitedExpanderExt2 {
331    /// Create a new expander with the given limit.
332    #[allow(dead_code)]
333    pub fn new(max_depth: usize) -> Self {
334        DepthLimitedExpanderExt2 {
335            max_depth,
336            current_depth: 0,
337        }
338    }
339    /// Returns true if we can still expand (not at limit).
340    #[allow(dead_code)]
341    pub fn can_expand(&self) -> bool {
342        self.current_depth < self.max_depth
343    }
344    /// Enter a new level of expansion.
345    #[allow(dead_code)]
346    pub fn enter(&mut self) -> bool {
347        if self.current_depth >= self.max_depth {
348            return false;
349        }
350        self.current_depth += 1;
351        true
352    }
353    /// Exit a level of expansion.
354    #[allow(dead_code)]
355    pub fn exit(&mut self) {
356        if self.current_depth > 0 {
357            self.current_depth -= 1;
358        }
359    }
360}
361/// The macro expansion engine.
362///
363/// Maintains a registry of macro definitions and provides expansion services.
364pub struct MacroExpander {
365    /// Registered macro definitions keyed by name.
366    macros: HashMap<String, MacroDef>,
367    /// Next available scope id for hygiene.
368    next_scope: u64,
369    /// Registered syntax definitions.
370    syntax_defs: Vec<SyntaxDef>,
371    /// Maximum expansion depth (to guard against infinite recursion).
372    pub(super) max_depth: u32,
373}
374impl MacroExpander {
375    /// Create a new macro expander.
376    pub fn new() -> Self {
377        Self {
378            macros: HashMap::new(),
379            next_scope: 1,
380            syntax_defs: Vec::new(),
381            max_depth: 128,
382        }
383    }
384    /// Set the maximum expansion depth.
385    pub fn set_max_depth(&mut self, depth: u32) {
386        self.max_depth = depth;
387    }
388    /// Generate a fresh scope id for hygiene.
389    pub fn fresh_scope(&mut self) -> u64 {
390        let id = self.next_scope;
391        self.next_scope += 1;
392        id
393    }
394    /// Register a macro definition.
395    pub fn register_macro(&mut self, def: MacroDef) {
396        self.macros.insert(def.name.clone(), def);
397    }
398    /// Unregister a macro by name.
399    pub fn unregister_macro(&mut self, name: &str) -> Option<MacroDef> {
400        self.macros.remove(name)
401    }
402    /// Check whether a macro with the given name is registered.
403    pub fn has_macro(&self, name: &str) -> bool {
404        self.macros.contains_key(name)
405    }
406    /// Get a macro definition by name.
407    pub fn get_macro(&self, name: &str) -> Option<&MacroDef> {
408        self.macros.get(name)
409    }
410    /// Get the number of registered macros.
411    pub fn macro_count(&self) -> usize {
412        self.macros.len()
413    }
414    /// Register a syntax definition.
415    pub fn register_syntax(&mut self, def: SyntaxDef) {
416        self.syntax_defs.push(def);
417    }
418    /// Get all syntax definitions for a given kind.
419    pub fn syntax_defs_for(&self, kind: &SyntaxKind) -> Vec<&SyntaxDef> {
420        self.syntax_defs
421            .iter()
422            .filter(|d| &d.kind == kind)
423            .collect()
424    }
425    /// Expand a macro invocation.
426    ///
427    /// Looks up the macro by `name`, tries each rule in order, and returns
428    /// the expanded token sequence on the first match.
429    #[allow(clippy::result_large_err)]
430    pub fn expand(&mut self, name: &str, input: &[Token]) -> Result<Vec<Token>, MacroError> {
431        self.expand_with_depth(name, input, 0)
432    }
433    /// Internal expansion with depth tracking.
434    #[allow(clippy::result_large_err)]
435    fn expand_with_depth(
436        &mut self,
437        name: &str,
438        input: &[Token],
439        depth: u32,
440    ) -> Result<Vec<Token>, MacroError> {
441        if depth > self.max_depth {
442            return Err(MacroError::new(
443                MacroErrorKind::ExpansionError,
444                format!(
445                    "maximum macro expansion depth ({}) exceeded for '{}'",
446                    self.max_depth, name
447                ),
448            ));
449        }
450        let def = self.macros.get(name).cloned().ok_or_else(|| {
451            MacroError::new(
452                MacroErrorKind::UnknownMacro,
453                format!("macro '{}' is not defined", name),
454            )
455        })?;
456        let mut matches = Vec::new();
457        for rule in &def.rules {
458            if let Some(bindings) = try_match_rule(rule, input) {
459                matches.push((rule.clone(), bindings));
460            }
461        }
462        match matches.len() {
463            0 => Err(MacroError::new(
464                MacroErrorKind::PatternMismatch,
465                format!(
466                    "no rule of macro '{}' matches the input ({} tokens)",
467                    name,
468                    input.len()
469                ),
470            )),
471            1 => {
472                let (rule, bindings) = matches
473                    .into_iter()
474                    .next()
475                    .expect("matches.len() == 1 per match arm");
476                let binding_slice: Vec<(String, Vec<Token>)> = bindings;
477                Ok(substitute(&rule.template, &binding_slice))
478            }
479            _ => Err(MacroError::new(
480                MacroErrorKind::AmbiguousMatch,
481                format!(
482                    "{} rules of macro '{}' match the input",
483                    matches.len(),
484                    name
485                ),
486            )),
487        }
488    }
489    /// List all registered macro names.
490    pub fn macro_names(&self) -> Vec<&str> {
491        let mut names: Vec<&str> = self.macros.keys().map(|s| s.as_str()).collect();
492        names.sort();
493        names
494    }
495}
496/// The result of a macro expansion attempt.
497#[allow(dead_code)]
498#[allow(missing_docs)]
499#[derive(Debug, Clone)]
500pub enum MacroExpansionResultExt2 {
501    /// Expansion succeeded, result is the expanded string
502    Success(String),
503    /// Expansion failed with an error
504    Error(MacroExpansionErrorExt2),
505    /// No rule matched
506    NoMatch,
507}
508impl MacroExpansionResultExt2 {
509    /// Returns true if expansion succeeded.
510    #[allow(dead_code)]
511    pub fn is_success(&self) -> bool {
512        matches!(self, MacroExpansionResultExt2::Success(_))
513    }
514    /// Returns the expanded string if successful.
515    #[allow(dead_code)]
516    pub fn as_str(&self) -> Option<&str> {
517        if let MacroExpansionResultExt2::Success(s) = self {
518            Some(s)
519        } else {
520            None
521        }
522    }
523}
524/// A macro template node (either a literal token or a variable reference).
525#[allow(dead_code)]
526#[allow(missing_docs)]
527#[derive(Debug, Clone)]
528pub enum MacroTemplateNodeExt {
529    /// A literal token
530    Literal(String),
531    /// A variable reference
532    Var(MacroVarExt),
533    /// A repetition block: separator and repeated body
534    Rep {
535        sep: Option<String>,
536        body: Vec<MacroTemplateNodeExt>,
537    },
538    /// A parenthesised group
539    Group(Vec<MacroTemplateNodeExt>),
540}
541/// A macro signature: name + param count.
542#[allow(dead_code)]
543#[allow(missing_docs)]
544#[derive(Debug, Clone)]
545pub struct MacroSignature {
546    /// Macro name
547    pub name: String,
548    /// Number of parameters
549    pub param_count: usize,
550}
551impl MacroSignature {
552    /// Create a new signature.
553    #[allow(dead_code)]
554    pub fn new(name: &str, param_count: usize) -> Self {
555        MacroSignature {
556            name: name.to_string(),
557            param_count,
558        }
559    }
560    /// Format as "name/N".
561    #[allow(dead_code)]
562    pub fn format(&self) -> String {
563        format!("{}/{}", self.name, self.param_count)
564    }
565}
566/// A macro definition with a name, parameter list, and template.
567#[allow(dead_code)]
568#[allow(missing_docs)]
569#[derive(Debug, Clone)]
570pub struct MacroDefinitionExt {
571    /// Macro name
572    pub name: String,
573    /// Parameter names
574    pub params: Vec<String>,
575    /// Template string
576    pub template: String,
577}
578impl MacroDefinitionExt {
579    /// Create a new macro definition.
580    #[allow(dead_code)]
581    pub fn new(name: &str, params: Vec<&str>, template: &str) -> Self {
582        MacroDefinitionExt {
583            name: name.to_string(),
584            params: params.into_iter().map(|s| s.to_string()).collect(),
585            template: template.to_string(),
586        }
587    }
588    /// Expand this macro with given arguments.
589    #[allow(dead_code)]
590    pub fn expand(&self, args: &[&str]) -> String {
591        if args.len() != self.params.len() {
592            return format!("(error: wrong arity for {})", self.name);
593        }
594        let mut env = std::collections::HashMap::new();
595        for (p, a) in self.params.iter().zip(args.iter()) {
596            env.insert(p.clone(), a.to_string());
597        }
598        let nodes = parse_simple_template_ext(&self.template);
599        expand_template_ext(&nodes, &env)
600    }
601}
602/// Macro expansion statistics.
603#[allow(dead_code)]
604#[allow(missing_docs)]
605#[derive(Debug, Clone, Default)]
606pub struct MacroStatsExt2 {
607    /// Total expansions attempted
608    pub attempts: usize,
609    /// Total successful expansions
610    pub successes: usize,
611    /// Total failures
612    pub failures: usize,
613    /// Maximum depth reached
614    pub max_depth: usize,
615}
616impl MacroStatsExt2 {
617    /// Record a successful expansion.
618    #[allow(dead_code)]
619    pub fn record_success(&mut self, depth: usize) {
620        self.attempts += 1;
621        self.successes += 1;
622        if depth > self.max_depth {
623            self.max_depth = depth;
624        }
625    }
626    /// Record a failed expansion.
627    #[allow(dead_code)]
628    pub fn record_failure(&mut self) {
629        self.attempts += 1;
630        self.failures += 1;
631    }
632    /// Returns the success rate as a fraction.
633    #[allow(dead_code)]
634    pub fn success_rate(&self) -> f64 {
635        if self.attempts == 0 {
636            return 1.0;
637        }
638        self.successes as f64 / self.attempts as f64
639    }
640}
641/// Kind of syntactic category that a `syntax` declaration extends.
642#[derive(Debug, Clone, PartialEq, Eq, Hash)]
643pub enum SyntaxKind {
644    /// Term-level syntax.
645    Term,
646    /// Top-level command syntax.
647    Command,
648    /// Tactic syntax.
649    Tactic,
650    /// Universe level syntax.
651    Level,
652    /// Attribute syntax.
653    Attr,
654}
655/// A hygiene context tracks fresh name generation for macro expansion.
656#[allow(dead_code)]
657#[allow(missing_docs)]
658#[derive(Debug, Clone, Default)]
659pub struct HygieneContextExt2 {
660    /// Counter for generating fresh names
661    pub counter: u32,
662    /// Prefix for generated names
663    pub prefix: String,
664}
665impl HygieneContextExt2 {
666    /// Create a new hygiene context.
667    #[allow(dead_code)]
668    pub fn new(prefix: &str) -> Self {
669        HygieneContextExt2 {
670            counter: 0,
671            prefix: prefix.to_string(),
672        }
673    }
674    /// Generate a fresh name.
675    #[allow(dead_code)]
676    pub fn fresh(&mut self) -> String {
677        let name = format!("{}{}", self.prefix, self.counter);
678        self.counter += 1;
679        name
680    }
681    /// Returns the number of names generated so far.
682    #[allow(dead_code)]
683    pub fn generated_count(&self) -> u32 {
684        self.counter
685    }
686}
687/// Token in macro pattern or template.
688#[derive(Debug, Clone, PartialEq)]
689pub enum MacroToken {
690    /// Literal token that must match exactly.
691    Literal(TokenKind),
692    /// Variable (matches any expression).
693    Var(String),
694    /// Repetition (zero or more of the sub-pattern).
695    Repeat(Vec<MacroToken>),
696    /// Optional (zero or one of the sub-pattern).
697    Optional(Vec<MacroToken>),
698    /// Syntax quotation (`` `(expr) ``).
699    Quote(Vec<MacroToken>),
700    /// Antiquotation splice (`$x`).
701    Antiquote(String),
702    /// Array splice (`$[x]*`).
703    SpliceArray(String),
704}
705/// A single macro rewrite rule: pattern => template.
706#[derive(Debug, Clone)]
707pub struct MacroRule {
708    /// Pattern to match.
709    pub pattern: Vec<MacroToken>,
710    /// Expansion template.
711    pub template: Vec<MacroToken>,
712}
713/// Hygiene information for macro expansion.
714///
715/// Tracks the scope and definition site so that names introduced by the macro
716/// do not accidentally capture or shadow names in the call site.
717#[derive(Debug, Clone, PartialEq, Eq)]
718pub struct HygieneInfo {
719    /// Unique scope identifier for this macro expansion.
720    pub scope_id: u64,
721    /// The source location where the macro was defined.
722    pub def_site: Span,
723}
724impl HygieneInfo {
725    /// Create new hygiene info.
726    pub fn new(scope_id: u64, def_site: Span) -> Self {
727        Self { scope_id, def_site }
728    }
729}
730/// A `syntax` declaration that extends a syntactic category.
731#[derive(Debug, Clone)]
732pub struct SyntaxDef {
733    /// Name of the syntax extension.
734    pub name: String,
735    /// Which syntactic category it extends.
736    pub kind: SyntaxKind,
737    /// The parser specification.
738    pub parser: Vec<SyntaxItem>,
739}
740impl SyntaxDef {
741    /// Create a new syntax definition.
742    pub fn new(name: String, kind: SyntaxKind, parser: Vec<SyntaxItem>) -> Self {
743        Self { name, kind, parser }
744    }
745    /// Number of parser items.
746    pub fn item_count(&self) -> usize {
747        self.parser.len()
748    }
749}
750/// A macro statistics tracker.
751#[allow(dead_code)]
752#[allow(missing_docs)]
753#[derive(Debug, Default)]
754pub struct MacroStats {
755    /// Number of expansions
756    pub expansions: usize,
757    /// Number of expansion errors
758    pub errors: usize,
759    /// Maximum expansion depth reached
760    pub max_depth: usize,
761}
762impl MacroStats {
763    /// Create a new empty stats record.
764    #[allow(dead_code)]
765    pub fn new() -> Self {
766        MacroStats::default()
767    }
768    /// Record a successful expansion.
769    #[allow(dead_code)]
770    pub fn record_success(&mut self, depth: usize) {
771        self.expansions += 1;
772        if depth > self.max_depth {
773            self.max_depth = depth;
774        }
775    }
776    /// Record an error.
777    #[allow(dead_code)]
778    pub fn record_error(&mut self) {
779        self.errors += 1;
780    }
781}
782/// Macro parser for parsing macro definitions.
783pub struct MacroParser {
784    /// Token stream.
785    tokens: Vec<Token>,
786    /// Current position.
787    pub(super) pos: usize,
788}
789impl MacroParser {
790    /// Create a new macro parser.
791    pub fn new(tokens: Vec<Token>) -> Self {
792        Self { tokens, pos: 0 }
793    }
794    /// Get current token.
795    fn current(&self) -> &Token {
796        self.tokens
797            .get(self.pos)
798            .unwrap_or(&self.tokens[self.tokens.len() - 1])
799    }
800    /// Check if at end of input.
801    fn is_eof(&self) -> bool {
802        matches!(self.current().kind, TokenKind::Eof)
803    }
804    /// Advance to next token.
805    fn advance(&mut self) -> Token {
806        let tok = self.current().clone();
807        if !self.is_eof() {
808            self.pos += 1;
809        }
810        tok
811    }
812    /// Parse a macro rule (pattern => template).
813    pub fn parse_rule(&mut self) -> Result<MacroRule, ParseError> {
814        let pattern = self.parse_macro_tokens()?;
815        if !matches!(self.current().kind, TokenKind::Arrow) {
816            return Err(ParseError::unexpected(
817                vec!["=>".to_string()],
818                self.current().kind.clone(),
819                self.current().span.clone(),
820            ));
821        }
822        self.advance();
823        let template = self.parse_macro_tokens()?;
824        Ok(MacroRule { pattern, template })
825    }
826    /// Parse multiple macro rules separated by `|`.
827    pub fn parse_rules(&mut self) -> Result<Vec<MacroRule>, ParseError> {
828        let mut rules = Vec::new();
829        rules.push(self.parse_rule()?);
830        while !self.is_eof() && matches!(self.current().kind, TokenKind::Bar) {
831            self.advance();
832            rules.push(self.parse_rule()?);
833        }
834        Ok(rules)
835    }
836    /// Parse macro tokens until a delimiter is reached.
837    fn parse_macro_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
838        let mut tokens = Vec::new();
839        while !self.is_eof() && !self.is_delimiter() {
840            tokens.push(self.parse_macro_token()?);
841        }
842        Ok(tokens)
843    }
844    /// Parse a single macro token.
845    pub(super) fn parse_macro_token(&mut self) -> Result<MacroToken, ParseError> {
846        let tok = self.current();
847        match &tok.kind {
848            TokenKind::Ident(name) if name.starts_with("$[") && name.ends_with("]*") => {
849                let inner = name[2..name.len() - 2].to_string();
850                self.advance();
851                Ok(MacroToken::SpliceArray(inner))
852            }
853            TokenKind::Ident(name) if name.starts_with('$') => {
854                let var_name = name[1..].to_string();
855                self.advance();
856                if var_name.is_empty() && matches!(self.current().kind, TokenKind::LParen) {
857                    self.advance();
858                    let inner = self.parse_group_tokens()?;
859                    if matches!(self.current().kind, TokenKind::RParen) {
860                        self.advance();
861                    }
862                    return match &self.current().kind {
863                        TokenKind::Star => {
864                            self.advance();
865                            Ok(MacroToken::Repeat(inner))
866                        }
867                        TokenKind::Question => {
868                            self.advance();
869                            Ok(MacroToken::Optional(inner))
870                        }
871                        _ => Ok(MacroToken::Repeat(inner)),
872                    };
873                }
874                if !var_name.is_empty()
875                    && !self.is_eof()
876                    && matches!(self.current().kind, TokenKind::LBracket)
877                    && self.pos + 2 < self.tokens.len()
878                    && matches!(self.tokens[self.pos + 1].kind, TokenKind::RBracket)
879                    && matches!(self.tokens[self.pos + 2].kind, TokenKind::Star)
880                {
881                    self.advance();
882                    self.advance();
883                    self.advance();
884                    return Ok(MacroToken::SpliceArray(var_name));
885                }
886                Ok(MacroToken::Var(var_name))
887            }
888            TokenKind::Ident(name) if name == "`" => {
889                self.advance();
890                if matches!(self.current().kind, TokenKind::LParen) {
891                    self.advance();
892                    let inner = self.parse_quoted_tokens()?;
893                    if matches!(self.current().kind, TokenKind::RParen) {
894                        self.advance();
895                    }
896                    Ok(MacroToken::Quote(inner))
897                } else {
898                    Ok(MacroToken::Literal(TokenKind::Ident("`".to_string())))
899                }
900            }
901            TokenKind::Star => {
902                let kind = tok.kind.clone();
903                self.advance();
904                Ok(MacroToken::Literal(kind))
905            }
906            TokenKind::LParen => {
907                let kind = tok.kind.clone();
908                self.advance();
909                Ok(MacroToken::Literal(kind))
910            }
911            _ => {
912                let kind = tok.kind.clone();
913                self.advance();
914                Ok(MacroToken::Literal(kind))
915            }
916        }
917    }
918    /// Parse tokens inside a `$(...)` repetition/optional group until the matching `)`.
919    ///
920    /// Handles nested parentheses so that inner `(...)` groups are consumed correctly.
921    fn parse_group_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
922        let mut tokens = Vec::new();
923        let mut depth = 1u32;
924        while !self.is_eof() {
925            match &self.current().kind {
926                TokenKind::LParen => {
927                    depth += 1;
928                    let kind = self.current().kind.clone();
929                    self.advance();
930                    tokens.push(MacroToken::Literal(kind));
931                }
932                TokenKind::RParen => {
933                    depth -= 1;
934                    if depth == 0 {
935                        break;
936                    }
937                    let kind = self.current().kind.clone();
938                    self.advance();
939                    tokens.push(MacroToken::Literal(kind));
940                }
941                _ => {
942                    tokens.push(self.parse_macro_token()?);
943                }
944            }
945        }
946        Ok(tokens)
947    }
948    /// Parse tokens inside a quotation until `)`.
949    fn parse_quoted_tokens(&mut self) -> Result<Vec<MacroToken>, ParseError> {
950        let mut tokens = Vec::new();
951        let mut depth = 1u32;
952        while !self.is_eof() {
953            if matches!(self.current().kind, TokenKind::LParen) {
954                depth += 1;
955            } else if matches!(self.current().kind, TokenKind::RParen) {
956                depth -= 1;
957                if depth == 0 {
958                    break;
959                }
960            }
961            tokens.push(self.parse_macro_token()?);
962        }
963        Ok(tokens)
964    }
965    /// Check if current token is a delimiter for macro token parsing.
966    fn is_delimiter(&self) -> bool {
967        matches!(
968            self.current().kind,
969            TokenKind::Arrow | TokenKind::Semicolon | TokenKind::RParen | TokenKind::Bar
970        )
971    }
972}
973/// A macro expansion depth limiter.
974#[allow(dead_code)]
975#[allow(missing_docs)]
976pub struct DepthLimitedExpander {
977    /// Maximum expansion depth
978    pub max_depth: usize,
979    /// Current depth
980    pub current_depth: usize,
981}
982impl DepthLimitedExpander {
983    /// Create a new expander.
984    #[allow(dead_code)]
985    pub fn new(max_depth: usize) -> Self {
986        DepthLimitedExpander {
987            max_depth,
988            current_depth: 0,
989        }
990    }
991    /// Try to expand (returns false if at limit).
992    #[allow(dead_code)]
993    pub fn try_expand(&mut self) -> bool {
994        if self.current_depth >= self.max_depth {
995            return false;
996        }
997        self.current_depth += 1;
998        true
999    }
1000    /// Exit a level.
1001    #[allow(dead_code)]
1002    pub fn exit(&mut self) {
1003        if self.current_depth > 0 {
1004            self.current_depth -= 1;
1005        }
1006    }
1007}
1008/// A hygiene context for macro expansion.
1009#[allow(dead_code)]
1010#[allow(missing_docs)]
1011#[derive(Debug, Clone)]
1012pub struct HygieneContext {
1013    /// Current expansion depth
1014    pub depth: usize,
1015    /// A unique tag for this expansion
1016    pub tag: u64,
1017}
1018impl HygieneContext {
1019    /// Create a new hygiene context.
1020    #[allow(dead_code)]
1021    pub fn new(tag: u64) -> Self {
1022        HygieneContext { depth: 0, tag }
1023    }
1024    /// Enter a nested expansion.
1025    #[allow(dead_code)]
1026    pub fn nested(&self) -> Self {
1027        HygieneContext {
1028            depth: self.depth + 1,
1029            tag: self.tag,
1030        }
1031    }
1032    /// Generate a hygienic name.
1033    #[allow(dead_code)]
1034    pub fn hygienic_name(&self, name: &str) -> String {
1035        format!("{}__{}_{}", name, self.tag, self.depth)
1036    }
1037}
1038/// A macro call site record.
1039#[allow(dead_code)]
1040#[allow(missing_docs)]
1041#[derive(Debug, Clone)]
1042pub struct MacroCallSiteExt {
1043    /// Name of the macro being called
1044    pub macro_name: String,
1045    /// Arguments provided
1046    pub args: Vec<String>,
1047    /// Byte offset of the call site
1048    pub offset: usize,
1049}
1050impl MacroCallSiteExt {
1051    /// Create a new call site.
1052    #[allow(dead_code)]
1053    pub fn new(macro_name: &str, args: Vec<&str>, offset: usize) -> Self {
1054        MacroCallSiteExt {
1055            macro_name: macro_name.to_string(),
1056            args: args.into_iter().map(|s| s.to_string()).collect(),
1057            offset,
1058        }
1059    }
1060}
1061/// An error that occurred during macro processing.
1062#[derive(Debug, Clone)]
1063pub struct MacroError {
1064    /// The kind of error.
1065    pub kind: MacroErrorKind,
1066    /// Optional source span where the error occurred.
1067    pub span: Option<Span>,
1068    /// Human-readable error message.
1069    pub message: String,
1070}
1071impl MacroError {
1072    /// Create a new macro error.
1073    pub fn new(kind: MacroErrorKind, message: String) -> Self {
1074        Self {
1075            kind,
1076            span: None,
1077            message,
1078        }
1079    }
1080    /// Attach a span to the error.
1081    pub fn with_span(mut self, span: Span) -> Self {
1082        self.span = Some(span);
1083        self
1084    }
1085}
1086/// A macro environment that stores all defined macros.
1087#[allow(dead_code)]
1088#[allow(missing_docs)]
1089pub struct MacroEnvironmentExt {
1090    /// All defined macros
1091    pub macros: Vec<MacroDefinitionExt>,
1092}
1093impl MacroEnvironmentExt {
1094    /// Create a new empty macro environment.
1095    #[allow(dead_code)]
1096    pub fn new() -> Self {
1097        MacroEnvironmentExt { macros: Vec::new() }
1098    }
1099    /// Define a new macro.
1100    #[allow(dead_code)]
1101    pub fn define(&mut self, def: MacroDefinitionExt) {
1102        self.macros.push(def);
1103    }
1104    /// Find a macro by name.
1105    #[allow(dead_code)]
1106    pub fn find(&self, name: &str) -> Option<&MacroDefinitionExt> {
1107        self.macros.iter().find(|m| m.name == name)
1108    }
1109    /// Expand a macro call.
1110    #[allow(dead_code)]
1111    pub fn expand_call(&self, name: &str, args: &[&str]) -> Option<String> {
1112        self.find(name).map(|m| m.expand(args))
1113    }
1114    /// Returns the number of defined macros.
1115    #[allow(dead_code)]
1116    pub fn len(&self) -> usize {
1117        self.macros.len()
1118    }
1119    /// Returns true if empty.
1120    #[allow(dead_code)]
1121    pub fn is_empty(&self) -> bool {
1122        self.macros.is_empty()
1123    }
1124}