Skip to main content

trampoline_parser/
codegen.rs

1//! Code generator for producing Rust parser code (scannerless)
2//!
3//! Generates:
4//! - Work enum (auto-named variants)
5//! - ParseResult enum
6//! - Parser struct with trampoline loop
7//! - Character-level matching functions
8
9use crate::CompiledGrammar;
10use crate::ir::{
11    CharClass, CombRef, Combinator, CombinatorIndex, CompiledCapDef, CompiledChoiceDef,
12    CompiledInfixOp, CompiledLookDef, CompiledLoopDef, CompiledMapDef, CompiledMemoDef,
13    CompiledOptDef, CompiledPostfixOp, CompiledPrattDef, CompiledPrefixOp, CompiledRuleDef,
14    CompiledSepByDef, CompiledSeqDef, CompiledSkipDef, CompiledTernaryOp, PatternInfo, PostfixOp,
15};
16
17/// Code generator
18pub struct CodeGenerator<'a> {
19    grammar: &'a CompiledGrammar,
20    output: String,
21    indent: usize,
22    /// Indexed combinator tables (populated during indexing pass)
23    index: CombinatorIndex,
24}
25
26impl<'a> CodeGenerator<'a> {
27    pub fn new(grammar: &'a CompiledGrammar) -> Self {
28        Self {
29            grammar,
30            output: String::new(),
31            indent: 0,
32            index: CombinatorIndex::default(),
33        }
34    }
35
36    /// Generate the complete parser code
37    ///
38    /// This generates a parser with ~45 fixed Work enum variants using indexed dispatch,
39    /// instead of O(grammar size) variants. The implementation uses static tables for
40    /// combinator definitions and table lookups for dispatch.
41    pub fn generate(mut self) -> String {
42        // Phase 1: Build combinator index
43        self.index_combinators();
44
45        // Phase 2: Emit code using indexed approach
46        self.emit_header();
47        self.emit_span();
48        self.emit_parse_error();
49        self.emit_parse_result_enum();
50        self.emit_helpers();
51        self.emit_builtin_helpers();
52        self.emit_static_tables();
53        self.emit_indexed_work_enum();
54        self.emit_indexed_parser();
55        self.output
56    }
57
58    /// Build the combinator index by traversing the grammar.
59    /// This assigns IDs to each combinator and builds lookup tables.
60    fn index_combinators(&mut self) {
61        // First pass: register all rule names so we can resolve references
62        for (i, rule) in self.grammar.rules.iter().enumerate() {
63            self.index.rule_map.insert(rule.name.clone(), i as u16);
64        }
65
66        // Second pass: index each rule's combinator tree
67        for rule in &self.grammar.rules {
68            let entry = self.index_combinator(&rule.combinator);
69            self.index.rules.push(CompiledRuleDef {
70                name: rule.name.clone(),
71                entry,
72            });
73        }
74    }
75
76    /// Recursively index a combinator, returning its CombRef
77    fn index_combinator(&mut self, comb: &Combinator) -> CombRef {
78        match comb {
79            Combinator::Rule(name) => {
80                // Look up the rule ID
81                if let Some(&rule_id) = self.index.rule_map.get(name) {
82                    CombRef::Rule(rule_id)
83                } else {
84                    // Rule not found - this should be caught by validation
85                    panic!("Unknown rule reference: {}", name);
86                }
87            }
88
89            Combinator::Sequence(items) => {
90                let compiled_items: Vec<CombRef> =
91                    items.iter().map(|c| self.index_combinator(c)).collect();
92                let seq_id = self.index.sequences.len() as u16;
93                self.index.sequences.push(CompiledSeqDef {
94                    items: compiled_items,
95                });
96                CombRef::Seq(seq_id)
97            }
98
99            Combinator::Choice(alts) => {
100                let compiled_alts: Vec<CombRef> =
101                    alts.iter().map(|c| self.index_combinator(c)).collect();
102                let choice_id = self.index.choices.len() as u16;
103                self.index.choices.push(CompiledChoiceDef {
104                    alts: compiled_alts,
105                });
106                CombRef::Choice(choice_id)
107            }
108
109            Combinator::ZeroOrMore(inner) => {
110                let inner_ref = self.index_combinator(inner);
111                let loop_id = self.index.zero_or_more.len() as u16;
112                self.index
113                    .zero_or_more
114                    .push(CompiledLoopDef { item: inner_ref });
115                CombRef::ZeroOrMore(loop_id)
116            }
117
118            Combinator::OneOrMore(inner) => {
119                let inner_ref = self.index_combinator(inner);
120                let loop_id = self.index.one_or_more.len() as u16;
121                self.index
122                    .one_or_more
123                    .push(CompiledLoopDef { item: inner_ref });
124                CombRef::OneOrMore(loop_id)
125            }
126
127            Combinator::Optional(inner) => {
128                let inner_ref = self.index_combinator(inner);
129                let opt_id = self.index.optionals.len() as u16;
130                self.index
131                    .optionals
132                    .push(CompiledOptDef { inner: inner_ref });
133                CombRef::Optional(opt_id)
134            }
135
136            Combinator::Literal(lit) => {
137                // Intern the literal
138                if let Some(&lit_id) = self.index.literal_map.get(lit) {
139                    CombRef::Literal(lit_id)
140                } else {
141                    let lit_id = self.index.literals.len() as u16;
142                    self.index.literal_map.insert(lit.clone(), lit_id);
143                    self.index.literals.push(lit.clone());
144                    CombRef::Literal(lit_id)
145                }
146            }
147
148            Combinator::Char(c) => CombRef::Char(*c),
149
150            Combinator::CharClass(class) => CombRef::CharClass(*class),
151
152            Combinator::CharRange(from, to) => CombRef::CharRange(*from, *to),
153
154            Combinator::AnyChar => CombRef::AnyChar,
155
156            Combinator::Capture(inner) => {
157                let inner_ref = self.index_combinator(inner);
158                let cap_id = self.index.captures.len() as u16;
159                self.index
160                    .captures
161                    .push(CompiledCapDef { inner: inner_ref });
162                CombRef::Capture(cap_id)
163            }
164
165            Combinator::NotFollowedBy(inner) => {
166                let inner_ref = self.index_combinator(inner);
167                let look_id = self.index.not_followed_by.len() as u16;
168                self.index
169                    .not_followed_by
170                    .push(CompiledLookDef { inner: inner_ref });
171                CombRef::NotFollowedBy(look_id)
172            }
173
174            Combinator::FollowedBy(inner) => {
175                let inner_ref = self.index_combinator(inner);
176                let look_id = self.index.followed_by.len() as u16;
177                self.index
178                    .followed_by
179                    .push(CompiledLookDef { inner: inner_ref });
180                CombRef::FollowedBy(look_id)
181            }
182
183            Combinator::Skip(inner) => {
184                let inner_ref = self.index_combinator(inner);
185                let skip_id = self.index.skips.len() as u16;
186                self.index.skips.push(CompiledSkipDef { inner: inner_ref });
187                CombRef::Skip(skip_id)
188            }
189
190            Combinator::SeparatedBy {
191                item,
192                separator,
193                trailing,
194            } => {
195                let item_ref = self.index_combinator(item);
196                let sep_ref = self.index_combinator(separator);
197                let sepby_id = self.index.separated_by.len() as u16;
198                self.index.separated_by.push(CompiledSepByDef {
199                    item: item_ref,
200                    separator: sep_ref,
201                    trailing: *trailing,
202                });
203                CombRef::SeparatedBy(sepby_id)
204            }
205
206            Combinator::Pratt(pratt_def) => {
207                let operand = pratt_def
208                    .operand
209                    .as_ref()
210                    .as_ref()
211                    .map(|c| self.index_combinator(c));
212
213                // Index prefix operators
214                let prefix_ops: Vec<CompiledPrefixOp> = pratt_def
215                    .prefix_ops
216                    .iter()
217                    .map(|op| {
218                        let pattern = self.extract_pattern_info(&op.pattern);
219                        let mapping_idx = self.intern_mapping(&op.mapping);
220                        CompiledPrefixOp {
221                            pattern,
222                            precedence: op.precedence,
223                            mapping_idx,
224                        }
225                    })
226                    .collect();
227
228                // Index infix operators
229                let infix_ops: Vec<CompiledInfixOp> = pratt_def
230                    .infix_ops
231                    .iter()
232                    .map(|op| {
233                        let pattern = self.extract_pattern_info(&op.pattern);
234                        let mapping_idx = self.intern_mapping(&op.mapping);
235                        CompiledInfixOp {
236                            pattern,
237                            precedence: op.precedence,
238                            assoc: op.assoc,
239                            mapping_idx,
240                        }
241                    })
242                    .collect();
243
244                // Index postfix operators
245                let postfix_ops: Vec<CompiledPostfixOp> = pratt_def
246                    .postfix_ops
247                    .iter()
248                    .map(|op| self.index_postfix_op(op))
249                    .collect();
250
251                // Index ternary operator
252                let ternary = pratt_def.ternary.as_ref().map(|t| {
253                    let first_lit = self.extract_literal(&t.first);
254                    let second_lit = self.extract_literal(&t.second);
255                    let mapping_idx = self.intern_mapping(&t.mapping);
256                    CompiledTernaryOp {
257                        first_lit,
258                        second_lit,
259                        precedence: t.precedence,
260                        mapping_idx,
261                    }
262                });
263
264                let has_infix_with_leading =
265                    infix_ops.iter().any(|op| op.pattern.leading_rule.is_some());
266                let has_prefix_with_leading = prefix_ops
267                    .iter()
268                    .any(|op| op.pattern.leading_rule.is_some());
269
270                let pratt_id = self.index.pratts.len() as u16;
271                self.index.pratts.push(CompiledPrattDef {
272                    operand,
273                    prefix_ops,
274                    infix_ops,
275                    postfix_ops,
276                    ternary,
277                    has_infix_with_leading,
278                    has_prefix_with_leading,
279                });
280                CombRef::Pratt(pratt_id)
281            }
282
283            Combinator::Mapped { inner, mapping } => {
284                let inner_ref = self.index_combinator(inner);
285                let mapping_idx = self.intern_mapping(mapping);
286                let map_id = self.index.mapped.len() as u16;
287                self.index.mapped.push(CompiledMapDef {
288                    inner: inner_ref,
289                    mapping_idx,
290                });
291                CombRef::Mapped(map_id)
292            }
293
294            Combinator::Memoize { id, inner } => {
295                let inner_ref = self.index_combinator(inner);
296                let memo_id = self.index.memoized.len() as u16;
297                self.index.memoized.push(CompiledMemoDef {
298                    memo_id: *id,
299                    inner: inner_ref,
300                });
301                CombRef::Memoize(memo_id)
302            }
303        }
304    }
305
306    /// Extract pattern information from an operator combinator
307    fn extract_pattern_info(&self, pattern: &Combinator) -> PatternInfo {
308        match pattern {
309            Combinator::Literal(lit) => PatternInfo {
310                literal: lit.clone(),
311                is_keyword: false,
312                not_followed_by: Vec::new(),
313                leading_rule: None,
314            },
315            Combinator::Sequence(items) => {
316                // Pattern like Sequence([Rule("ws"), Literal("+")])
317                // or Sequence([Literal("+"), NotFollowedBy(...)])
318                let mut pattern_info = PatternInfo {
319                    literal: String::new(),
320                    is_keyword: false,
321                    not_followed_by: Vec::new(),
322                    leading_rule: None,
323                };
324
325                for item in items {
326                    match item {
327                        Combinator::Rule(name) => {
328                            if pattern_info.literal.is_empty() {
329                                // Leading rule (e.g., whitespace)
330                                pattern_info.leading_rule = Some(name.clone());
331                            }
332                        }
333                        Combinator::Literal(lit) => {
334                            pattern_info.literal = lit.clone();
335                        }
336                        Combinator::NotFollowedBy(inner) => {
337                            // Extract characters/strings that must not follow
338                            if let Combinator::CharClass(CharClass::IdentCont) = inner.as_ref() {
339                                pattern_info.is_keyword = true;
340                            } else if let Combinator::Char(c) = inner.as_ref() {
341                                pattern_info.not_followed_by.push(c.to_string());
342                            } else if let Combinator::Literal(lit) = inner.as_ref() {
343                                pattern_info.not_followed_by.push(lit.clone());
344                            } else if let Combinator::Choice(alts) = inner.as_ref() {
345                                // Handle Choice of literals like choice((lit("<"), lit("=")))
346                                for alt in alts {
347                                    if let Combinator::Literal(lit) = alt {
348                                        pattern_info.not_followed_by.push(lit.clone());
349                                    } else if let Combinator::Char(c) = alt {
350                                        pattern_info.not_followed_by.push(c.to_string());
351                                    }
352                                }
353                            }
354                        }
355                        _ => {}
356                    }
357                }
358
359                pattern_info
360            }
361            _ => PatternInfo {
362                literal: String::new(),
363                is_keyword: false,
364                not_followed_by: Vec::new(),
365                leading_rule: None,
366            },
367        }
368    }
369
370    /// Extract a literal string from a combinator
371    fn extract_literal(&self, comb: &Combinator) -> String {
372        match comb {
373            Combinator::Literal(lit) => lit.clone(),
374            Combinator::Sequence(items) => {
375                // Look for literal in sequence
376                for item in items {
377                    if let Combinator::Literal(lit) = item {
378                        return lit.clone();
379                    }
380                }
381                String::new()
382            }
383            _ => String::new(),
384        }
385    }
386
387    /// Intern a mapping function string, returning its index
388    fn intern_mapping(&mut self, mapping: &str) -> usize {
389        // Check if we already have this mapping
390        for (i, existing) in self.index.mappings.iter().enumerate() {
391            if existing == mapping {
392                return i;
393            }
394        }
395        // Add new mapping
396        let idx = self.index.mappings.len();
397        self.index.mappings.push(mapping.to_string());
398        idx
399    }
400
401    /// Index a postfix operator
402    fn index_postfix_op(&mut self, op: &PostfixOp) -> CompiledPostfixOp {
403        match op {
404            PostfixOp::Simple {
405                pattern,
406                precedence,
407                mapping,
408            } => {
409                let pattern_info = self.extract_pattern_info(pattern);
410                let mapping_idx = self.intern_mapping(mapping);
411                CompiledPostfixOp::Simple {
412                    pattern: pattern_info,
413                    precedence: *precedence,
414                    mapping_idx,
415                }
416            }
417            PostfixOp::Call {
418                open,
419                close,
420                separator,
421                arg_rule,
422                precedence,
423                mapping,
424            } => {
425                let open_lit = self.extract_literal(open);
426                let close_lit = self.extract_literal(close);
427                let sep_lit = self.extract_literal(separator);
428                let arg_rule_id = arg_rule
429                    .as_ref()
430                    .and_then(|name| self.index.rule_map.get(name).copied());
431                let mapping_idx = self.intern_mapping(mapping);
432                CompiledPostfixOp::Call {
433                    open_lit,
434                    close_lit,
435                    sep_lit,
436                    arg_rule: arg_rule_id,
437                    precedence: *precedence,
438                    mapping_idx,
439                }
440            }
441            PostfixOp::Index {
442                open,
443                close,
444                precedence,
445                mapping,
446            } => {
447                let open_lit = self.extract_literal(open);
448                let close_lit = self.extract_literal(close);
449                let mapping_idx = self.intern_mapping(mapping);
450                CompiledPostfixOp::Index {
451                    open_lit,
452                    close_lit,
453                    precedence: *precedence,
454                    mapping_idx,
455                }
456            }
457            PostfixOp::Member {
458                pattern,
459                precedence,
460                mapping,
461            } => {
462                let pattern_info = self.extract_pattern_info(pattern);
463                let mapping_idx = self.intern_mapping(mapping);
464                CompiledPostfixOp::Member {
465                    pattern: pattern_info,
466                    precedence: *precedence,
467                    mapping_idx,
468                }
469            }
470            PostfixOp::Rule {
471                rule_name,
472                precedence,
473                mapping,
474            } => {
475                let rule_id = self
476                    .index
477                    .rule_map
478                    .get(rule_name)
479                    .copied()
480                    .unwrap_or_else(|| panic!("Unknown rule in postfix: {}", rule_name));
481                let mapping_idx = self.intern_mapping(mapping);
482                CompiledPostfixOp::Rule {
483                    rule_id,
484                    precedence: *precedence,
485                    mapping_idx,
486                }
487            }
488        }
489    }
490
491    fn emit_helpers(&mut self) {
492        for helper in &self.grammar.ast_config.helper_code {
493            self.output.push_str(helper);
494            self.blank();
495        }
496    }
497
498    fn emit_builtin_helpers(&mut self) {
499        let string_type = self
500            .grammar
501            .ast_config
502            .string_type
503            .as_deref()
504            .unwrap_or("String");
505        // Helper function to decode unicode escapes in identifiers
506        self.line("/// Decode unicode escape sequences in identifier text");
507        self.line(&format!(
508            "fn decode_identifier_escapes(text: &{}) -> {} {{",
509            string_type, string_type
510        ));
511        self.indent += 1;
512        // For String type, use as_str(); for custom types use as_ref()
513        if string_type == "String" {
514            self.line("let s: &str = text.as_str();");
515        } else {
516            self.line("let s: &str = text.as_ref();");
517        }
518        self.line("if !s.contains('\\\\') { return text.clone(); }");
519        self.line("let mut result = String::with_capacity(s.len());");
520        self.line("let mut chars = s.chars().peekable();");
521        self.line("while let Some(c) = chars.next() {");
522        self.indent += 1;
523        self.line("if c == '\\\\' && chars.peek() == Some(&'u') {");
524        self.indent += 1;
525        self.line("chars.next();");
526        self.line("if chars.peek() == Some(&'{') {");
527        self.indent += 1;
528        self.line("chars.next();");
529        self.line("let mut hex = String::new();");
530        self.line("while let Some(&h) = chars.peek() {");
531        self.indent += 1;
532        self.line("if h == '}' { chars.next(); break; }");
533        self.line("chars.next(); hex.push(h);");
534        self.indent -= 1;
535        self.line("}");
536        self.line("if let Ok(code) = u32::from_str_radix(&hex, 16) {");
537        self.indent += 1;
538        self.line("if let Some(ch) = char::from_u32(code) { result.push(ch); }");
539        self.indent -= 1;
540        self.line("}");
541        self.indent -= 1;
542        self.line("} else {");
543        self.indent += 1;
544        self.line("let mut hex = String::new();");
545        self.line("for _ in 0..4 { if let Some(h) = chars.next() { hex.push(h); } }");
546        self.line("if let Ok(code) = u32::from_str_radix(&hex, 16) {");
547        self.indent += 1;
548        self.line("if let Some(ch) = char::from_u32(code) { result.push(ch); }");
549        self.indent -= 1;
550        self.line("}");
551        self.indent -= 1;
552        self.line("}");
553        self.indent -= 1;
554        self.line("} else { result.push(c); }");
555        self.indent -= 1;
556        self.line("}");
557        // For String type, just return the result directly; for custom types, use From
558        if string_type == "String" {
559            self.line("result");
560        } else {
561            self.line(&format!("{}::from(result)", string_type));
562        }
563        self.indent -= 1;
564        self.line("}");
565        self.blank();
566    }
567
568    fn emit_helper_methods(&mut self, string_type: &str) {
569        // Current char
570        self.line("fn current_char(&self) -> Option<char> {");
571        self.indent += 1;
572        self.line("self.input.get(self.pos..).and_then(|s| s.chars().next())");
573        self.indent -= 1;
574        self.line("}");
575        self.blank();
576
577        // Advance by one character and track line/column
578        self.line("fn advance(&mut self) {");
579        self.indent += 1;
580        self.line("if let Some(c) = self.current_char() {");
581        self.indent += 1;
582        self.line("self.pos += c.len_utf8();");
583        self.line("if c == '\\n' {");
584        self.indent += 1;
585        self.line("self.line += 1;");
586        self.line("self.column = 1;");
587        self.indent -= 1;
588        self.line("} else {");
589        self.indent += 1;
590        self.line("self.column += 1;");
591        self.indent -= 1;
592        self.line("}");
593        self.indent -= 1;
594        self.line("}");
595        self.indent -= 1;
596        self.line("}");
597        self.blank();
598
599        // Match literal with line tracking
600        self.line("fn match_literal(&mut self, lit: &str) -> bool {");
601        self.indent += 1;
602        self.line("if self.input.get(self.pos..).is_some_and(|s| s.starts_with(lit)) {");
603        self.indent += 1;
604        self.line("for c in lit.chars() {");
605        self.indent += 1;
606        self.line("self.pos += c.len_utf8();");
607        self.line("if c == '\\n' {");
608        self.indent += 1;
609        self.line("self.line += 1;");
610        self.line("self.column = 1;");
611        self.indent -= 1;
612        self.line("} else {");
613        self.indent += 1;
614        self.line("self.column += 1;");
615        self.indent -= 1;
616        self.line("}");
617        self.indent -= 1;
618        self.line("}");
619        self.line("true");
620        self.indent -= 1;
621        self.line("} else {");
622        self.indent += 1;
623        self.line("false");
624        self.indent -= 1;
625        self.line("}");
626        self.indent -= 1;
627        self.line("}");
628        self.blank();
629
630        // Match char class with line tracking
631        self.line("fn match_char_class(&mut self, class: fn(char) -> bool) -> Option<char> {");
632        self.indent += 1;
633        self.line("if let Some(c) = self.current_char() {");
634        self.indent += 1;
635        self.line("if class(c) {");
636        self.indent += 1;
637        self.line("self.pos += c.len_utf8();");
638        self.line("if c == '\\n' {");
639        self.indent += 1;
640        self.line("self.line += 1;");
641        self.line("self.column = 1;");
642        self.indent -= 1;
643        self.line("} else {");
644        self.indent += 1;
645        self.line("self.column += 1;");
646        self.indent -= 1;
647        self.line("}");
648        self.line("return Some(c);");
649        self.indent -= 1;
650        self.line("}");
651        self.indent -= 1;
652        self.line("}");
653        self.line("None");
654        self.indent -= 1;
655        self.line("}");
656        self.blank();
657
658        // Create span at current position
659        self.line("fn make_span(&self, start: usize) -> Span {");
660        self.indent += 1;
661        self.line("Span {");
662        self.indent += 1;
663        self.line("start,");
664        self.line("end: self.pos,");
665        self.line("line: self.line,");
666        self.line("column: self.column,");
667        self.indent -= 1;
668        self.line("}");
669        self.indent -= 1;
670        self.line("}");
671        self.blank();
672
673        // Create text result
674        self.line(&format!(
675            "fn text_result(&self, start: usize, end: usize) -> {} {{",
676            string_type
677        ));
678        self.indent += 1;
679        if string_type == "String" {
680            self.line("self.input.get(start..end).unwrap_or(\"\").to_string()");
681        } else {
682            // For custom string types like JsString, assume From<&str>
683            self.line(&format!(
684                "{}::from(self.input.get(start..end).unwrap_or(\"\"))",
685                string_type
686            ));
687        }
688        self.indent -= 1;
689        self.line("}");
690        self.blank();
691
692        // Make error
693        self.line("fn make_error(&self, msg: &str) -> ParseError {");
694        self.indent += 1;
695        self.line("ParseError {");
696        self.indent += 1;
697        self.line("message: msg.to_string(),");
698        self.line(
699            "span: Span { start: self.pos, end: self.pos, line: self.line, column: self.column },",
700        );
701        self.indent -= 1;
702        self.line("}");
703        self.indent -= 1;
704        self.line("}");
705        self.blank();
706
707        // Try to consume a literal (for Pratt parsing)
708        self.line("fn try_consume(&mut self, s: &str) -> bool {");
709        self.indent += 1;
710        self.line(
711            "if self.input.get(self.pos..).is_some_and(|remaining| remaining.starts_with(s)) {",
712        );
713        self.indent += 1;
714        self.line("for c in s.chars() {");
715        self.indent += 1;
716        self.line("if c == '\\n' {");
717        self.indent += 1;
718        self.line("self.line += 1;");
719        self.line("self.column = 1;");
720        self.indent -= 1;
721        self.line("} else {");
722        self.indent += 1;
723        self.line("self.column += 1;");
724        self.indent -= 1;
725        self.line("}");
726        self.indent -= 1;
727        self.line("}");
728        self.line("self.pos += s.len();");
729        self.line("true");
730        self.indent -= 1;
731        self.line("} else {");
732        self.indent += 1;
733        self.line("false");
734        self.indent -= 1;
735        self.line("}");
736        self.indent -= 1;
737        self.line("}");
738        self.blank();
739    }
740
741    fn emit_apply_mapping_method(&mut self) {
742        if self.index.mapped.is_empty() {
743            // No mappings - generate a stub that just returns the input unchanged
744            self.line(
745                "fn apply_mapping(&self, _map_id: u16, r: ParseResult, _span: Span) -> Result<ParseResult, ParseError> {",
746            );
747            self.indent += 1;
748            self.line("Ok(r)");
749            self.indent -= 1;
750            self.line("}");
751            self.blank();
752            return;
753        }
754
755        // Collect mapping info first to avoid borrow conflict
756        let mapping_arms: Vec<(usize, String)> = self
757            .index
758            .mapped
759            .iter()
760            .enumerate()
761            .map(|(map_id, mapped_def)| {
762                let mapping_fn = self.index.mappings[mapped_def.mapping_idx].clone();
763                (map_id, mapping_fn)
764            })
765            .collect();
766
767        self.line(
768            "fn apply_mapping(&self, map_id: u16, r: ParseResult, span: Span) -> Result<ParseResult, ParseError> {",
769        );
770        self.indent += 1;
771        self.line("match map_id {");
772        self.indent += 1;
773
774        // Generate an arm for each mapping
775        for (map_id, mapping_fn) in mapping_arms {
776            self.line(&format!("{} => {{", map_id));
777            self.indent += 1;
778            self.line(&format!("let mapping_fn = {};", mapping_fn));
779            self.line("mapping_fn(r, span)");
780            self.indent -= 1;
781            self.line("}");
782        }
783
784        // Default arm
785        self.line("_ => Ok(r),");
786        self.indent -= 1;
787        self.line("}");
788        self.indent -= 1;
789        self.line("}");
790        self.blank();
791    }
792
793    fn line(&mut self, s: &str) {
794        for _ in 0..self.indent {
795            self.output.push_str("    ");
796        }
797        self.output.push_str(s);
798        self.output.push('\n');
799    }
800
801    fn blank(&mut self) {
802        self.output.push('\n');
803    }
804
805    fn emit_header(&mut self) {
806        self.line("// Auto-generated parser - DO NOT EDIT");
807        self.line("//");
808        self.line("// Generated by trampoline-parser (scannerless)");
809        self.blank();
810
811        // Emit user imports
812        for import in &self.grammar.ast_config.imports {
813            self.line(&format!("use {};", import));
814        }
815        if !self.grammar.ast_config.imports.is_empty() {
816            self.blank();
817        }
818    }
819
820    fn emit_span(&mut self) {
821        if !self.grammar.ast_config.generate_span {
822            return;
823        }
824        self.line("/// Source location span");
825        self.line("#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]");
826        self.line("pub struct Span {");
827        self.indent += 1;
828        self.line("pub start: usize,");
829        self.line("pub end: usize,");
830        self.line("pub line: u32,");
831        self.line("pub column: u32,");
832        self.indent -= 1;
833        self.line("}");
834        self.blank();
835    }
836
837    fn emit_parse_error(&mut self) {
838        if !self.grammar.ast_config.generate_parse_error {
839            return;
840        }
841        self.line("/// Parse error");
842        self.line("#[derive(Debug, Clone)]");
843        self.line("pub struct ParseError {");
844        self.indent += 1;
845        self.line("pub message: String,");
846        self.line("pub span: Span,");
847        self.indent -= 1;
848        self.line("}");
849        self.blank();
850        self.line("impl ParseError {");
851        self.indent += 1;
852        self.line("pub fn new(message: String, line: u32, column: u32) -> Self {");
853        self.indent += 1;
854        self.line("Self { message, span: Span { start: 0, end: 0, line, column } }");
855        self.indent -= 1;
856        self.line("}");
857        self.indent -= 1;
858        self.line("}");
859        self.blank();
860        self.line("impl core::fmt::Display for ParseError {");
861        self.indent += 1;
862        self.line("fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {");
863        self.indent += 1;
864        self.line("write!(f, \"{} at {}..{}\", self.message, self.span.start, self.span.end)");
865        self.indent -= 1;
866        self.line("}");
867        self.indent -= 1;
868        self.line("}");
869        self.blank();
870        self.line("impl core::error::Error for ParseError {}");
871        self.blank();
872    }
873
874    fn emit_parse_result_enum(&mut self) {
875        if !self.grammar.ast_config.generate_parse_result {
876            return;
877        }
878
879        let string_type = self
880            .grammar
881            .ast_config
882            .string_type
883            .as_deref()
884            .unwrap_or("String");
885
886        self.line("/// Parse result value");
887        self.line("#[derive(Debug, Clone)]");
888        self.line("pub enum ParseResult {");
889        self.indent += 1;
890        self.line("/// No value (for skipped items)");
891        self.line("None,");
892        self.line("/// Captured text");
893        self.line(&format!("Text({}, Span),", string_type));
894        self.line("/// List of results");
895        self.line("List(Vec<ParseResult>),");
896
897        // Emit custom variants
898        for variant in &self.grammar.ast_config.result_variants {
899            self.line(&format!("{}({}),", variant.name, variant.rust_type));
900        }
901
902        self.indent -= 1;
903        self.line("}");
904        self.blank();
905
906        // Emit helper methods
907        self.line("impl ParseResult {");
908        self.indent += 1;
909        self.line("pub fn span(&self) -> Span {");
910        self.indent += 1;
911        self.line("match self {");
912        self.indent += 1;
913        self.line("ParseResult::None => Span::default(),");
914        self.line("ParseResult::Text(_, span) => *span,");
915        self.line("ParseResult::List(items) => {");
916        self.indent += 1;
917        self.line("if items.is_empty() { return Span::default(); }");
918        self.line("let first_span = items.first().map(|i| i.span()).unwrap_or_default();");
919        self.line("let last_span = items.last().map(|i| i.span()).unwrap_or_default();");
920        self.line("Span { start: first_span.start, end: last_span.end, line: first_span.line, column: first_span.column }");
921        self.indent -= 1;
922        self.line("}");
923        for variant in &self.grammar.ast_config.result_variants {
924            if let Some(ref span_expr) = variant.span_expr {
925                self.line(&format!(
926                    "ParseResult::{}(v) => {},",
927                    variant.name,
928                    span_expr.replace('_', "v")
929                ));
930            } else {
931                self.line(&format!(
932                    "ParseResult::{}(_) => Span::default(),",
933                    variant.name
934                ));
935            }
936        }
937        self.indent -= 1;
938        self.line("}");
939        self.indent -= 1;
940        self.line("}");
941        self.indent -= 1;
942        self.line("}");
943        self.blank();
944    }
945
946    // ========================================================================
947    // Indexed code generation (reduced enum variants)
948    // ========================================================================
949
950    /// Emit the fixed Work enum with indexed variants
951    fn emit_indexed_work_enum(&mut self) {
952        self.line("/// Work items for the trampoline (state-indexed)");
953        self.line("#[derive(Debug, Clone)]");
954        self.line("enum Work {");
955        self.indent += 1;
956
957        // Rule dispatch
958        self.line("/// Dispatch to a rule by ID");
959        self.line("Rule { rule_id: u16, result_base: usize },");
960        self.blank();
961
962        // Sequence variants (3)
963        self.line("/// Start a sequence");
964        self.line("SeqStart { seq_id: u16, result_base: usize },");
965        self.line("/// Continue to next step in sequence");
966        self.line("SeqStep { seq_id: u16, step: u8, result_base: usize, seq_base: usize },");
967        self.line("/// Complete a sequence");
968        self.line("SeqComplete { seq_id: u16, result_base: usize, seq_base: usize },");
969        self.blank();
970
971        // Choice variants (2)
972        self.line("/// Start a choice");
973        self.line("ChoiceStart { choice_id: u16, result_base: usize },");
974        self.line("/// Try next alternative in choice");
975        self.line("ChoiceTry { choice_id: u16, alt: u8, result_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32, stack_base: usize },");
976        self.blank();
977
978        // ZeroOrMore variants (3)
979        self.line("/// Start zero-or-more loop");
980        self.line("ZeroOrMoreStart { loop_id: u16, result_base: usize },");
981        self.line("/// Continue zero-or-more loop");
982        self.line("ZeroOrMoreLoop { loop_id: u16, result_base: usize, loop_base: usize, iter_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
983        self.line("/// Complete zero-or-more loop");
984        self.line("ZeroOrMoreComplete { loop_id: u16, result_base: usize, loop_base: usize },");
985        self.blank();
986
987        // OneOrMore variants (3)
988        self.line("/// Start one-or-more loop");
989        self.line("OneOrMoreStart { loop_id: u16, result_base: usize },");
990        self.line("/// Continue one-or-more loop");
991        self.line("OneOrMoreLoop { loop_id: u16, result_base: usize, loop_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32, count: usize },");
992        self.line("/// Complete one-or-more loop");
993        self.line("OneOrMoreComplete { loop_id: u16, result_base: usize, loop_base: usize },");
994        self.blank();
995
996        // Optional variants (2)
997        self.line("/// Start optional");
998        self.line("OptionalStart { opt_id: u16, result_base: usize },");
999        self.line("/// Check optional result");
1000        self.line("OptionalCheck { opt_id: u16, result_base: usize, opt_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
1001        self.blank();
1002
1003        // Capture variants (2)
1004        self.line("/// Start capture");
1005        self.line("CaptureStart { cap_id: u16, result_base: usize },");
1006        self.line("/// Complete capture");
1007        self.line("CaptureComplete { cap_id: u16, result_base: usize, capture_base: usize, start_pos: usize, start_line: u32, start_column: u32 },");
1008        self.blank();
1009
1010        // Lookahead variants (4)
1011        self.line("/// Start not-followed-by");
1012        self.line("NotFollowedByStart { look_id: u16, result_base: usize },");
1013        self.line("/// Check not-followed-by result");
1014        self.line("NotFollowedByCheck { look_id: u16, result_base: usize, look_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
1015        self.line("/// Start followed-by");
1016        self.line("FollowedByStart { look_id: u16, result_base: usize },");
1017        self.line("/// Check followed-by result");
1018        self.line("FollowedByCheck { look_id: u16, result_base: usize, look_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
1019        self.blank();
1020
1021        // Skip variants (2)
1022        self.line("/// Start skip");
1023        self.line("SkipStart { skip_id: u16, result_base: usize },");
1024        self.line("/// Complete skip");
1025        self.line("SkipComplete { skip_id: u16, result_base: usize, skip_base: usize },");
1026        self.blank();
1027
1028        // SeparatedBy variants (4)
1029        self.line("/// Start separated-by");
1030        self.line("SepByStart { sepby_id: u16, result_base: usize },");
1031        self.line("/// Parse separator in separated-by");
1032        self.line("SepBySep { sepby_id: u16, result_base: usize, list_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
1033        self.line("/// Parse item in separated-by");
1034        self.line("SepByItem { sepby_id: u16, result_base: usize, list_base: usize, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32 },");
1035        self.line("/// Complete separated-by");
1036        self.line("SepByComplete { sepby_id: u16, result_base: usize, list_base: usize },");
1037        self.blank();
1038
1039        // Mapped variants (2)
1040        self.line("/// Start mapped combinator");
1041        self.line("MappedStart { map_id: u16, result_base: usize },");
1042        self.line("/// Apply mapping function");
1043        self.line("MappedApply { map_id: u16, result_base: usize, map_base: usize, start_pos: usize, start_line: u32, start_column: u32 },");
1044        self.blank();
1045
1046        // Memoize variants (2)
1047        self.line("/// Start memoized combinator");
1048        self.line("MemoStart { memo_id: u16, result_base: usize },");
1049        self.line("/// Complete memoized combinator");
1050        self.line("MemoComplete { memo_id: u16, result_base: usize, start_pos: usize, inner_base: usize },");
1051        self.blank();
1052
1053        // Pratt parsing variants (~15)
1054        self.line("/// Start Pratt expression parsing");
1055        self.line("PrattStart { pratt_id: u16, result_base: usize },");
1056        self.line("/// Parse Pratt operand");
1057        self.line("PrattParseOperand { pratt_id: u16, result_base: usize, min_prec: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1058        self.line("/// After parsing Pratt operand");
1059        self.line("PrattAfterOperand { pratt_id: u16, result_base: usize, min_prec: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1060        self.line("/// After parsing Pratt prefix operator");
1061        self.line("PrattAfterPrefix { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1062        self.line("/// After parsing Pratt infix operator RHS");
1063        self.line("PrattAfterInfix { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1064        self.line("/// Check for Pratt postfix operator");
1065        self.line("PrattCheckPostfix { pratt_id: u16, result_base: usize, min_prec: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1066        self.line("/// After parsing simple Pratt postfix");
1067        self.line("PrattAfterPostfixSimple { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1068        self.line("/// Parse Pratt call argument");
1069        self.line("PrattPostfixCallArg { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, args_base: usize, start_pos: usize, start_line: u32, start_column: u32 },");
1070        self.line("/// Parse Pratt call separator");
1071        self.line("PrattPostfixCallSep { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, args_base: usize, start_pos: usize, start_line: u32, start_column: u32 },");
1072        self.line("/// After parsing Pratt call");
1073        self.line("PrattAfterPostfixCall { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, args_base: usize, start_pos: usize, start_line: u32, start_column: u32 },");
1074        self.line("/// After parsing Pratt index");
1075        self.line("PrattAfterPostfixIndex { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1076        self.line("/// After parsing Pratt member access");
1077        self.line("PrattAfterPostfixMember { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1078        self.line("/// After parsing Pratt rule-based postfix");
1079        self.line("PrattAfterPostfixRule { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1080        self.line("/// After parsing ternary first operand");
1081        self.line("PrattAfterTernaryFirst { pratt_id: u16, result_base: usize, min_prec: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1082        self.line("/// After parsing ternary second operand");
1083        self.line("PrattAfterTernarySecond { pratt_id: u16, result_base: usize, min_prec: u8, start_pos: usize, start_line: u32, start_column: u32 },");
1084        self.line("/// After parsing infix leading rule");
1085        self.line("PrattAfterInfixLeadingRule { pratt_id: u16, result_base: usize, min_prec: u8, op_idx: u8, next_prec: u8, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32, start_pos: usize, start_line: u32, start_column: u32 },");
1086        self.line("/// After parsing prefix leading rule");
1087        self.line("PrattAfterPrefixLeadingRule { pratt_id: u16, result_base: usize, min_prec: u8, checkpoint: usize, checkpoint_line: u32, checkpoint_column: u32, start_pos: usize, start_line: u32, start_column: u32 },");
1088        self.blank();
1089
1090        // Terminal execution (immediate, no work item needed, but we keep for dispatch uniformity)
1091        self.line("/// Execute a literal match");
1092        self.line("Literal { lit_id: u16, result_base: usize },");
1093        self.line("/// Execute a char class match");
1094        self.line("CharClass { class: u8, result_base: usize },");
1095        self.line("/// Execute a char range match");
1096        self.line("CharRange { from: char, to: char, result_base: usize },");
1097        self.line("/// Execute a specific char match");
1098        self.line("Char { ch: char, result_base: usize },");
1099        self.line("/// Match any char");
1100        self.line("AnyChar { result_base: usize },");
1101
1102        self.indent -= 1;
1103        self.line("}");
1104        self.blank();
1105    }
1106
1107    /// Emit static dispatch tables for indexed code generation
1108    fn emit_static_tables(&mut self) {
1109        // Pre-collect all data to avoid borrow conflicts
1110        let seq_lines: Vec<String> = self
1111            .index
1112            .sequences
1113            .iter()
1114            .map(|seq| {
1115                let items: Vec<String> = seq.items.iter().map(combref_to_code).collect();
1116                format!("&[{}],", items.join(", "))
1117            })
1118            .collect();
1119
1120        let choice_lines: Vec<String> = self
1121            .index
1122            .choices
1123            .iter()
1124            .map(|choice| {
1125                let alts: Vec<String> = choice.alts.iter().map(combref_to_code).collect();
1126                format!("&[{}],", alts.join(", "))
1127            })
1128            .collect();
1129
1130        let zero_or_more_lines: Vec<String> = self
1131            .index
1132            .zero_or_more
1133            .iter()
1134            .map(|l| format!("{},", combref_to_code(&l.item)))
1135            .collect();
1136
1137        let one_or_more_lines: Vec<String> = self
1138            .index
1139            .one_or_more
1140            .iter()
1141            .map(|l| format!("{},", combref_to_code(&l.item)))
1142            .collect();
1143
1144        let optional_lines: Vec<String> = self
1145            .index
1146            .optionals
1147            .iter()
1148            .map(|o| format!("{},", combref_to_code(&o.inner)))
1149            .collect();
1150
1151        let capture_lines: Vec<String> = self
1152            .index
1153            .captures
1154            .iter()
1155            .map(|c| format!("{},", combref_to_code(&c.inner)))
1156            .collect();
1157
1158        let nfb_lines: Vec<String> = self
1159            .index
1160            .not_followed_by
1161            .iter()
1162            .map(|l| format!("{},", combref_to_code(&l.inner)))
1163            .collect();
1164
1165        let fb_lines: Vec<String> = self
1166            .index
1167            .followed_by
1168            .iter()
1169            .map(|l| format!("{},", combref_to_code(&l.inner)))
1170            .collect();
1171
1172        let skip_lines: Vec<String> = self
1173            .index
1174            .skips
1175            .iter()
1176            .map(|s| format!("{},", combref_to_code(&s.inner)))
1177            .collect();
1178
1179        let sepby_lines: Vec<String> = self
1180            .index
1181            .separated_by
1182            .iter()
1183            .map(|s| {
1184                format!(
1185                    "({}, {}, {}),",
1186                    combref_to_code(&s.item),
1187                    combref_to_code(&s.separator),
1188                    s.trailing
1189                )
1190            })
1191            .collect();
1192
1193        let mapped_lines: Vec<String> = self
1194            .index
1195            .mapped
1196            .iter()
1197            .map(|m| format!("({}, {}),", combref_to_code(&m.inner), m.mapping_idx))
1198            .collect();
1199
1200        let memo_lines: Vec<String> = self
1201            .index
1202            .memoized
1203            .iter()
1204            .map(|m| format!("({}, {}),", m.memo_id, combref_to_code(&m.inner)))
1205            .collect();
1206
1207        let literal_lines: Vec<String> = self
1208            .index
1209            .literals
1210            .iter()
1211            .map(|l| format!("{:?},", l))
1212            .collect();
1213
1214        let rule_lines: Vec<String> = self
1215            .index
1216            .rules
1217            .iter()
1218            .map(|r| format!("{},", combref_to_code(&r.entry)))
1219            .collect();
1220
1221        // Now emit all the collected data
1222        // CombRef enum
1223        self.line("/// Reference to a combinator by type and index");
1224        self.line("#[derive(Debug, Clone, Copy)]");
1225        self.line("#[allow(dead_code)]");
1226        self.line("enum CombRef {");
1227        self.indent += 1;
1228        self.line("Rule(u16),");
1229        self.line("Seq(u16),");
1230        self.line("Choice(u16),");
1231        self.line("ZeroOrMore(u16),");
1232        self.line("OneOrMore(u16),");
1233        self.line("Optional(u16),");
1234        self.line("Literal(u16),");
1235        self.line("CharClass(u8),");
1236        self.line("CharRange(char, char),");
1237        self.line("Char(char),");
1238        self.line("AnyChar,");
1239        self.line("Capture(u16),");
1240        self.line("NotFollowedBy(u16),");
1241        self.line("FollowedBy(u16),");
1242        self.line("Skip(u16),");
1243        self.line("SeparatedBy(u16),");
1244        self.line("Pratt(u16),");
1245        self.line("Mapped(u16),");
1246        self.line("Memoize(u16),");
1247        self.indent -= 1;
1248        self.line("}");
1249        self.blank();
1250
1251        // Sequence definitions
1252        self.line("/// Sequence combinator definitions");
1253        self.line("static SEQUENCES: &[&[CombRef]] = &[");
1254        self.indent += 1;
1255        for line in &seq_lines {
1256            self.line(line);
1257        }
1258        self.indent -= 1;
1259        self.line("];");
1260        self.blank();
1261
1262        // Choice definitions
1263        self.line("/// Choice combinator definitions");
1264        self.line("static CHOICES: &[&[CombRef]] = &[");
1265        self.indent += 1;
1266        for line in &choice_lines {
1267            self.line(line);
1268        }
1269        self.indent -= 1;
1270        self.line("];");
1271        self.blank();
1272
1273        // Loop definitions (ZeroOrMore)
1274        self.line("/// ZeroOrMore loop definitions");
1275        self.line("static ZERO_OR_MORE: &[CombRef] = &[");
1276        self.indent += 1;
1277        for line in &zero_or_more_lines {
1278            self.line(line);
1279        }
1280        self.indent -= 1;
1281        self.line("];");
1282        self.blank();
1283
1284        // Loop definitions (OneOrMore)
1285        self.line("/// OneOrMore loop definitions");
1286        self.line("static ONE_OR_MORE: &[CombRef] = &[");
1287        self.indent += 1;
1288        for line in &one_or_more_lines {
1289            self.line(line);
1290        }
1291        self.indent -= 1;
1292        self.line("];");
1293        self.blank();
1294
1295        // Optional definitions
1296        self.line("/// Optional combinator definitions");
1297        self.line("static OPTIONALS: &[CombRef] = &[");
1298        self.indent += 1;
1299        for line in &optional_lines {
1300            self.line(line);
1301        }
1302        self.indent -= 1;
1303        self.line("];");
1304        self.blank();
1305
1306        // Capture definitions
1307        self.line("/// Capture combinator definitions");
1308        self.line("static CAPTURES: &[CombRef] = &[");
1309        self.indent += 1;
1310        for line in &capture_lines {
1311            self.line(line);
1312        }
1313        self.indent -= 1;
1314        self.line("];");
1315        self.blank();
1316
1317        // Lookahead definitions
1318        self.line("/// NotFollowedBy combinator definitions");
1319        self.line("static NOT_FOLLOWED_BY: &[CombRef] = &[");
1320        self.indent += 1;
1321        for line in &nfb_lines {
1322            self.line(line);
1323        }
1324        self.indent -= 1;
1325        self.line("];");
1326        self.blank();
1327
1328        self.line("/// FollowedBy combinator definitions");
1329        self.line("static FOLLOWED_BY: &[CombRef] = &[");
1330        self.indent += 1;
1331        for line in &fb_lines {
1332            self.line(line);
1333        }
1334        self.indent -= 1;
1335        self.line("];");
1336        self.blank();
1337
1338        // Skip definitions
1339        self.line("/// Skip combinator definitions");
1340        self.line("static SKIPS: &[CombRef] = &[");
1341        self.indent += 1;
1342        for line in &skip_lines {
1343            self.line(line);
1344        }
1345        self.indent -= 1;
1346        self.line("];");
1347        self.blank();
1348
1349        // SeparatedBy definitions
1350        self.line("/// SeparatedBy combinator definitions (item, separator, trailing)");
1351        self.line("static SEPARATED_BY: &[(CombRef, CombRef, bool)] = &[");
1352        self.indent += 1;
1353        for line in &sepby_lines {
1354            self.line(line);
1355        }
1356        self.indent -= 1;
1357        self.line("];");
1358        self.blank();
1359
1360        // Mapped definitions
1361        self.line("/// Mapped combinator definitions (inner, mapping_idx)");
1362        self.line("static MAPPED: &[(CombRef, usize)] = &[");
1363        self.indent += 1;
1364        for line in &mapped_lines {
1365            self.line(line);
1366        }
1367        self.indent -= 1;
1368        self.line("];");
1369        self.blank();
1370
1371        // Memoize definitions
1372        self.line("/// Memoize combinator definitions (memo_id, inner)");
1373        self.line("static MEMOIZED: &[(usize, CombRef)] = &[");
1374        self.indent += 1;
1375        for line in &memo_lines {
1376            self.line(line);
1377        }
1378        self.indent -= 1;
1379        self.line("];");
1380        self.blank();
1381
1382        // Literals table
1383        self.line("/// Literal strings table");
1384        self.line("static LITERALS: &[&str] = &[");
1385        self.indent += 1;
1386        for line in &literal_lines {
1387            self.line(line);
1388        }
1389        self.indent -= 1;
1390        self.line("];");
1391        self.blank();
1392
1393        // Rule entry points
1394        self.line("/// Rule entry points");
1395        self.line("static RULES: &[CombRef] = &[");
1396        self.indent += 1;
1397        for line in &rule_lines {
1398            self.line(line);
1399        }
1400        self.indent -= 1;
1401        self.line("];");
1402        self.blank();
1403
1404        // Emit Pratt static tables
1405        self.emit_pratt_static_tables();
1406    }
1407
1408    /// Emit Pratt parsing static tables
1409    fn emit_pratt_static_tables(&mut self) {
1410        if self.index.pratts.is_empty() {
1411            return;
1412        }
1413
1414        // Pratt operator structs
1415        self.line("/// Pratt prefix operator definition");
1416        self.line("#[derive(Debug, Clone)]");
1417        self.line("struct PrattPrefixOp {");
1418        self.indent += 1;
1419        self.line("literal: &'static str,");
1420        self.line("precedence: u8,");
1421        self.line("is_keyword: bool,");
1422        self.line("not_followed_by: &'static [&'static str],");
1423        self.line("leading_rule: Option<u16>,");
1424        self.indent -= 1;
1425        self.line("}");
1426        self.blank();
1427
1428        self.line("/// Pratt infix operator definition");
1429        self.line("#[derive(Debug, Clone)]");
1430        self.line("struct PrattInfixOp {");
1431        self.indent += 1;
1432        self.line("literal: &'static str,");
1433        self.line("precedence: u8,");
1434        self.line("is_left_assoc: bool,");
1435        self.line("is_keyword: bool,");
1436        self.line("not_followed_by: &'static [&'static str],");
1437        self.line("leading_rule: Option<u16>,");
1438        self.indent -= 1;
1439        self.line("}");
1440        self.blank();
1441
1442        self.line("/// Pratt postfix operator kind");
1443        self.line("#[derive(Debug, Clone, Copy)]");
1444        self.line("enum PostfixKind {");
1445        self.indent += 1;
1446        self.line("Simple,");
1447        self.line("Call,");
1448        self.line("Index,");
1449        self.line("Member,");
1450        self.line("Rule,");
1451        self.indent -= 1;
1452        self.line("}");
1453        self.blank();
1454
1455        self.line("/// Pratt postfix operator definition");
1456        self.line("#[derive(Debug, Clone)]");
1457        self.line("struct PrattPostfixOp {");
1458        self.indent += 1;
1459        self.line("kind: PostfixKind,");
1460        self.line("open_lit: &'static str,");
1461        self.line("close_lit: &'static str,");
1462        self.line("sep_lit: &'static str,");
1463        self.line("precedence: u8,");
1464        self.line("not_followed_by: &'static [&'static str],");
1465        self.line("arg_rule: Option<u16>,");
1466        self.line("member_rule: Option<u16>,");
1467        self.line("rule_name_id: Option<u16>,");
1468        self.indent -= 1;
1469        self.line("}");
1470        self.blank();
1471
1472        self.line("/// Pratt ternary operator definition");
1473        self.line("#[derive(Debug, Clone)]");
1474        self.line("struct PrattTernaryOp {");
1475        self.indent += 1;
1476        self.line("first_lit: &'static str,");
1477        self.line("second_lit: &'static str,");
1478        self.line("precedence: u8,");
1479        self.indent -= 1;
1480        self.line("}");
1481        self.blank();
1482
1483        self.line("/// Pratt parser definition");
1484        self.line("#[derive(Debug, Clone)]");
1485        self.line("struct PrattDef {");
1486        self.indent += 1;
1487        self.line("operand: Option<CombRef>,");
1488        self.line("prefix_ops: &'static [PrattPrefixOp],");
1489        self.line("infix_ops: &'static [PrattInfixOp],");
1490        self.line("postfix_ops: &'static [PrattPostfixOp],");
1491        self.line("ternary: Option<PrattTernaryOp>,");
1492        self.line("has_infix_with_leading: bool,");
1493        self.line("has_prefix_with_leading: bool,");
1494        self.indent -= 1;
1495        self.line("}");
1496        self.blank();
1497
1498        // Build Pratt definition data
1499        let pratt_defs: Vec<String> = self.build_pratt_defs();
1500
1501        // Emit PRATTS static array
1502        self.line("/// Pratt parser definitions");
1503        self.line("static PRATTS: &[PrattDef] = &[");
1504        self.indent += 1;
1505        for def in &pratt_defs {
1506            self.line(def);
1507        }
1508        self.indent -= 1;
1509        self.line("];");
1510        self.blank();
1511
1512        // Emit static arrays for each Pratt's operators
1513        self.emit_pratt_operator_arrays();
1514    }
1515
1516    /// Build Pratt definition strings for the static array
1517    fn build_pratt_defs(&self) -> Vec<String> {
1518        self.index
1519            .pratts
1520            .iter()
1521            .enumerate()
1522            .map(|(pratt_idx, pratt)| {
1523                let operand = match &pratt.operand {
1524                    Some(cr) => format!("Some({})", combref_to_code(cr)),
1525                    None => "None".to_string(),
1526                };
1527                let ternary = match &pratt.ternary {
1528                    Some(t) => format!(
1529                        "Some(PrattTernaryOp {{ first_lit: {:?}, second_lit: {:?}, precedence: {} }})",
1530                        t.first_lit, t.second_lit, t.precedence
1531                    ),
1532                    None => "None".to_string(),
1533                };
1534                format!(
1535                    "PrattDef {{ operand: {}, prefix_ops: &PRATT_{}_PREFIX, infix_ops: &PRATT_{}_INFIX, postfix_ops: &PRATT_{}_POSTFIX, ternary: {}, has_infix_with_leading: {}, has_prefix_with_leading: {} }},",
1536                    operand, pratt_idx, pratt_idx, pratt_idx, ternary, pratt.has_infix_with_leading, pratt.has_prefix_with_leading
1537                )
1538            })
1539            .collect()
1540    }
1541
1542    /// Emit operator arrays for each Pratt parser
1543    #[allow(clippy::type_complexity)]
1544    fn emit_pratt_operator_arrays(&mut self) {
1545        // Pre-collect all data to avoid borrow conflicts
1546        let pratt_arrays: Vec<(usize, Vec<String>, Vec<String>, Vec<String>)> = self
1547            .index
1548            .pratts
1549            .iter()
1550            .enumerate()
1551            .map(|(pratt_idx, pratt)| {
1552                // Prefix operators
1553                let prefix_lines: Vec<String> = pratt
1554                    .prefix_ops
1555                    .iter()
1556                    .map(|prefix_op| {
1557                        let nfb: Vec<String> = prefix_op
1558                            .pattern
1559                            .not_followed_by
1560                            .iter()
1561                            .map(|s| format!("{:?}", s))
1562                            .collect();
1563                        let leading = match &prefix_op.pattern.leading_rule {
1564                            Some(name) => {
1565                                let rule_id = self.index.rule_map.get(name).copied().unwrap_or(0);
1566                                format!("Some({})", rule_id)
1567                            }
1568                            None => "None".to_string(),
1569                        };
1570                        format!(
1571                            "PrattPrefixOp {{ literal: {:?}, precedence: {}, is_keyword: {}, not_followed_by: &[{}], leading_rule: {} }},",
1572                            prefix_op.pattern.literal,
1573                            prefix_op.precedence,
1574                            prefix_op.pattern.is_keyword,
1575                            nfb.join(", "),
1576                            leading
1577                        )
1578                    })
1579                    .collect();
1580
1581                // Infix operators
1582                let infix_lines: Vec<String> = pratt
1583                    .infix_ops
1584                    .iter()
1585                    .map(|infix_op| {
1586                        let nfb: Vec<String> = infix_op
1587                            .pattern
1588                            .not_followed_by
1589                            .iter()
1590                            .map(|s| format!("{:?}", s))
1591                            .collect();
1592                        let leading = match &infix_op.pattern.leading_rule {
1593                            Some(name) => {
1594                                let rule_id = self.index.rule_map.get(name).copied().unwrap_or(0);
1595                                format!("Some({})", rule_id)
1596                            }
1597                            None => "None".to_string(),
1598                        };
1599                        format!(
1600                            "PrattInfixOp {{ literal: {:?}, precedence: {}, is_left_assoc: {}, is_keyword: {}, not_followed_by: &[{}], leading_rule: {} }},",
1601                            infix_op.pattern.literal,
1602                            infix_op.precedence,
1603                            infix_op.assoc == crate::Assoc::Left,
1604                            infix_op.pattern.is_keyword,
1605                            nfb.join(", "),
1606                            leading
1607                        )
1608                    })
1609                    .collect();
1610
1611                // Postfix operators
1612                let postfix_lines: Vec<String> = pratt
1613                    .postfix_ops
1614                    .iter()
1615                    .map(|postfix_op| {
1616                        let (kind, open, close, sep, prec, nfb, arg_rule, member_rule, rule_name_id) =
1617                            match postfix_op {
1618                                CompiledPostfixOp::Simple { pattern, precedence, .. } => {
1619                                    let nfb: Vec<String> = pattern
1620                                        .not_followed_by
1621                                        .iter()
1622                                        .map(|s| format!("{:?}", s))
1623                                        .collect();
1624                                    (
1625                                        "PostfixKind::Simple",
1626                                        pattern.literal.clone(),
1627                                        String::new(),
1628                                        String::new(),
1629                                        *precedence,
1630                                        nfb,
1631                                        "None".to_string(),
1632                                        "None".to_string(),
1633                                        "None".to_string(),
1634                                    )
1635                                }
1636                                CompiledPostfixOp::Call {
1637                                    open_lit,
1638                                    close_lit,
1639                                    sep_lit,
1640                                    arg_rule,
1641                                    precedence,
1642                                    ..
1643                                } => {
1644                                    let ar = match arg_rule {
1645                                        Some(id) => format!("Some({})", id),
1646                                        None => "None".to_string(),
1647                                    };
1648                                    (
1649                                        "PostfixKind::Call",
1650                                        open_lit.clone(),
1651                                        close_lit.clone(),
1652                                        sep_lit.clone(),
1653                                        *precedence,
1654                                        vec![],
1655                                        ar,
1656                                        "None".to_string(),
1657                                        "None".to_string(),
1658                                    )
1659                                }
1660                                CompiledPostfixOp::Index {
1661                                    open_lit,
1662                                    close_lit,
1663                                    precedence,
1664                                    ..
1665                                } => (
1666                                    "PostfixKind::Index",
1667                                    open_lit.clone(),
1668                                    close_lit.clone(),
1669                                    String::new(),
1670                                    *precedence,
1671                                    vec![],
1672                                    "None".to_string(),
1673                                    "None".to_string(),
1674                                    "None".to_string(),
1675                                ),
1676                                CompiledPostfixOp::Member { pattern, precedence, .. } => {
1677                                    let nfb: Vec<String> = pattern
1678                                        .not_followed_by
1679                                        .iter()
1680                                        .map(|c| format!("{:?}", c.to_string()))
1681                                        .collect();
1682                                    (
1683                                        "PostfixKind::Member",
1684                                        pattern.literal.clone(),
1685                                        String::new(),
1686                                        String::new(),
1687                                        *precedence,
1688                                        nfb,
1689                                        "None".to_string(),
1690                                        "None".to_string(),
1691                                        "None".to_string(),
1692                                    )
1693                                }
1694                                CompiledPostfixOp::Rule { rule_id, precedence, .. } => (
1695                                    "PostfixKind::Rule",
1696                                    String::new(),
1697                                    String::new(),
1698                                    String::new(),
1699                                    *precedence,
1700                                    vec![],
1701                                    "None".to_string(),
1702                                    "None".to_string(),
1703                                    format!("Some({})", rule_id),
1704                                ),
1705                            };
1706                        format!(
1707                            "PrattPostfixOp {{ kind: {}, open_lit: {:?}, close_lit: {:?}, sep_lit: {:?}, precedence: {}, not_followed_by: &[{}], arg_rule: {}, member_rule: {}, rule_name_id: {} }},",
1708                            kind, open, close, sep, prec, nfb.join(", "), arg_rule, member_rule, rule_name_id
1709                        )
1710                    })
1711                    .collect();
1712
1713                (pratt_idx, prefix_lines, infix_lines, postfix_lines)
1714            })
1715            .collect();
1716
1717        // Now emit all collected data
1718        for (pratt_idx, prefix_lines, infix_lines, postfix_lines) in pratt_arrays {
1719            // Prefix operators
1720            self.line(&format!(
1721                "static PRATT_{}_PREFIX: &[PrattPrefixOp] = &[",
1722                pratt_idx
1723            ));
1724            self.indent += 1;
1725            for line in &prefix_lines {
1726                self.line(line);
1727            }
1728            self.indent -= 1;
1729            self.line("];");
1730
1731            // Infix operators
1732            self.line(&format!(
1733                "static PRATT_{}_INFIX: &[PrattInfixOp] = &[",
1734                pratt_idx
1735            ));
1736            self.indent += 1;
1737            for line in &infix_lines {
1738                self.line(line);
1739            }
1740            self.indent -= 1;
1741            self.line("];");
1742
1743            // Postfix operators
1744            self.line(&format!(
1745                "static PRATT_{}_POSTFIX: &[PrattPostfixOp] = &[",
1746                pratt_idx
1747            ));
1748            self.indent += 1;
1749            for line in &postfix_lines {
1750                self.line(line);
1751            }
1752            self.indent -= 1;
1753            self.line("];");
1754            self.blank();
1755        }
1756    }
1757
1758    /// Emit the dispatch_combref helper for indexed generation
1759    fn emit_dispatch_combref(&mut self) {
1760        self.line("/// Push work item for a CombRef");
1761        self.line("fn dispatch_combref(&mut self, cref: CombRef, result_base: usize) {");
1762        self.indent += 1;
1763        self.line("match cref {");
1764        self.indent += 1;
1765        self.line(
1766            "CombRef::Rule(id) => self.work_stack.push(Work::Rule { rule_id: id, result_base }),",
1767        );
1768        self.line(
1769            "CombRef::Seq(id) => self.work_stack.push(Work::SeqStart { seq_id: id, result_base }),",
1770        );
1771        self.line("CombRef::Choice(id) => self.work_stack.push(Work::ChoiceStart { choice_id: id, result_base }),");
1772        self.line("CombRef::ZeroOrMore(id) => self.work_stack.push(Work::ZeroOrMoreStart { loop_id: id, result_base }),");
1773        self.line("CombRef::OneOrMore(id) => self.work_stack.push(Work::OneOrMoreStart { loop_id: id, result_base }),");
1774        self.line("CombRef::Optional(id) => self.work_stack.push(Work::OptionalStart { opt_id: id, result_base }),");
1775        self.line("CombRef::Literal(id) => self.work_stack.push(Work::Literal { lit_id: id, result_base }),");
1776        self.line("CombRef::CharClass(class) => self.work_stack.push(Work::CharClass { class, result_base }),");
1777        self.line("CombRef::CharRange(from, to) => self.work_stack.push(Work::CharRange { from, to, result_base }),");
1778        self.line("CombRef::Char(ch) => self.work_stack.push(Work::Char { ch, result_base }),");
1779        self.line("CombRef::AnyChar => self.work_stack.push(Work::AnyChar { result_base }),");
1780        self.line("CombRef::Capture(id) => self.work_stack.push(Work::CaptureStart { cap_id: id, result_base }),");
1781        self.line("CombRef::NotFollowedBy(id) => self.work_stack.push(Work::NotFollowedByStart { look_id: id, result_base }),");
1782        self.line("CombRef::FollowedBy(id) => self.work_stack.push(Work::FollowedByStart { look_id: id, result_base }),");
1783        self.line("CombRef::Skip(id) => self.work_stack.push(Work::SkipStart { skip_id: id, result_base }),");
1784        self.line("CombRef::SeparatedBy(id) => self.work_stack.push(Work::SepByStart { sepby_id: id, result_base }),");
1785        self.line("CombRef::Pratt(id) => self.work_stack.push(Work::PrattStart { pratt_id: id, result_base }),");
1786        self.line("CombRef::Mapped(id) => self.work_stack.push(Work::MappedStart { map_id: id, result_base }),");
1787        self.line("CombRef::Memoize(id) => self.work_stack.push(Work::MemoStart { memo_id: id, result_base }),");
1788        self.indent -= 1;
1789        self.line("}");
1790        self.indent -= 1;
1791        self.line("}");
1792        self.blank();
1793    }
1794
1795    /// Emit the indexed execute method
1796    fn emit_indexed_execute(&mut self) {
1797        self.line("fn execute(&mut self, work: Work) -> Result<(), ParseError> {");
1798        self.indent += 1;
1799        self.line("match work {");
1800        self.indent += 1;
1801
1802        // Rule dispatch
1803        self.line("Work::Rule { rule_id, result_base } => {");
1804        self.indent += 1;
1805        self.line("if let Some(&entry) = RULES.get(rule_id as usize) {");
1806        self.indent += 1;
1807        self.line("self.dispatch_combref(entry, result_base);");
1808        self.indent -= 1;
1809        self.line("}");
1810        self.indent -= 1;
1811        self.line("}");
1812        self.blank();
1813
1814        // Sequence handlers
1815        self.emit_indexed_seq_handlers();
1816
1817        // Choice handlers
1818        self.emit_indexed_choice_handlers();
1819
1820        // ZeroOrMore handlers
1821        self.emit_indexed_zero_or_more_handlers();
1822
1823        // OneOrMore handlers
1824        self.emit_indexed_one_or_more_handlers();
1825
1826        // Optional handlers
1827        self.emit_indexed_optional_handlers();
1828
1829        // Capture handlers
1830        self.emit_indexed_capture_handlers();
1831
1832        // Lookahead handlers
1833        self.emit_indexed_lookahead_handlers();
1834
1835        // Skip handlers
1836        self.emit_indexed_skip_handlers();
1837
1838        // SeparatedBy handlers
1839        self.emit_indexed_separated_by_handlers();
1840
1841        // Mapped handlers
1842        self.emit_indexed_mapped_handlers();
1843
1844        // Memoize handlers
1845        self.emit_indexed_memoize_handlers();
1846
1847        // Terminal handlers
1848        self.emit_indexed_terminal_handlers();
1849
1850        // Pratt handlers (simplified - will need full implementation)
1851        self.emit_indexed_pratt_handlers();
1852
1853        self.indent -= 1;
1854        self.line("}");
1855        self.line("Ok(())");
1856        self.indent -= 1;
1857        self.line("}");
1858        self.blank();
1859    }
1860
1861    fn emit_indexed_seq_handlers(&mut self) {
1862        // SeqStart
1863        self.line("Work::SeqStart { seq_id, result_base } => {");
1864        self.indent += 1;
1865        self.line("if let Some(items) = SEQUENCES.get(seq_id as usize) {");
1866        self.indent += 1;
1867        self.line("let seq_base = self.result_stack.len();");
1868        self.line("self.work_stack.push(Work::SeqComplete { seq_id, result_base, seq_base });");
1869        self.line("// Push steps in reverse order");
1870        self.line("for i in (1..items.len()).rev() {");
1871        self.indent += 1;
1872        self.line(
1873            "self.work_stack.push(Work::SeqStep { seq_id, step: i as u8, result_base, seq_base });",
1874        );
1875        self.indent -= 1;
1876        self.line("}");
1877        self.line("// Dispatch first item");
1878        self.line("if let Some(&first) = items.first() {");
1879        self.indent += 1;
1880        self.line("self.dispatch_combref(first, result_base);");
1881        self.indent -= 1;
1882        self.line("}");
1883        self.indent -= 1;
1884        self.line("}");
1885        self.indent -= 1;
1886        self.line("}");
1887        self.blank();
1888
1889        // SeqStep
1890        self.line("Work::SeqStep { seq_id, step, result_base, seq_base } => {");
1891        self.indent += 1;
1892        self.line("if self.last_error.is_some() { return Ok(()); }");
1893        self.line("if let Some(items) = SEQUENCES.get(seq_id as usize) {");
1894        self.indent += 1;
1895        self.line("if let Some(&item) = items.get(step as usize) {");
1896        self.indent += 1;
1897        self.line("self.dispatch_combref(item, result_base);");
1898        self.indent -= 1;
1899        self.line("}");
1900        self.indent -= 1;
1901        self.line("}");
1902        self.indent -= 1;
1903        self.line("}");
1904        self.blank();
1905
1906        // SeqComplete
1907        self.line("Work::SeqComplete { seq_id: _, result_base: _, seq_base } => {");
1908        self.indent += 1;
1909        self.line("if self.last_error.is_none() {");
1910        self.indent += 1;
1911        self.line("let results: Vec<_> = self.result_stack.drain(seq_base..).collect();");
1912        self.line("self.result_stack.push(ParseResult::List(results));");
1913        self.indent -= 1;
1914        self.line("} else {");
1915        self.indent += 1;
1916        self.line("self.result_stack.truncate(seq_base);");
1917        self.indent -= 1;
1918        self.line("}");
1919        self.indent -= 1;
1920        self.line("}");
1921        self.blank();
1922    }
1923
1924    fn emit_indexed_choice_handlers(&mut self) {
1925        // ChoiceStart
1926        self.line("Work::ChoiceStart { choice_id, result_base } => {");
1927        self.indent += 1;
1928        self.line("let checkpoint = self.pos;");
1929        self.line("let checkpoint_line = self.line;");
1930        self.line("let checkpoint_column = self.column;");
1931        self.line("let stack_base = self.result_stack.len();");
1932        self.line("if let Some(alts) = CHOICES.get(choice_id as usize) {");
1933        self.indent += 1;
1934        self.line("self.work_stack.push(Work::ChoiceTry { choice_id, alt: 0, result_base, checkpoint, checkpoint_line, checkpoint_column, stack_base });");
1935        self.line("if let Some(&first) = alts.first() {");
1936        self.indent += 1;
1937        self.line("self.dispatch_combref(first, result_base);");
1938        self.indent -= 1;
1939        self.line("}");
1940        self.indent -= 1;
1941        self.line("}");
1942        self.indent -= 1;
1943        self.line("}");
1944        self.blank();
1945
1946        // ChoiceTry
1947        self.line("Work::ChoiceTry { choice_id, alt, result_base, checkpoint, checkpoint_line, checkpoint_column, stack_base } => {");
1948        self.indent += 1;
1949        self.line("if self.last_error.is_some() {");
1950        self.indent += 1;
1951        self.line("self.last_error = None;");
1952        self.line("self.pos = checkpoint;");
1953        self.line("self.line = checkpoint_line;");
1954        self.line("self.column = checkpoint_column;");
1955        self.line("self.result_stack.truncate(stack_base);");
1956        self.line("if let Some(alts) = CHOICES.get(choice_id as usize) {");
1957        self.indent += 1;
1958        self.line("let next_alt = alt + 1;");
1959        self.line("if let Some(&next_comb) = alts.get(next_alt as usize) {");
1960        self.indent += 1;
1961        self.line("self.work_stack.push(Work::ChoiceTry { choice_id, alt: next_alt, result_base, checkpoint, checkpoint_line, checkpoint_column, stack_base });");
1962        self.line("self.dispatch_combref(next_comb, result_base);");
1963        self.indent -= 1;
1964        self.line("} else {");
1965        self.indent += 1;
1966        self.line("self.last_error = Some(self.make_error(\"no alternative matched\"));");
1967        self.indent -= 1;
1968        self.line("}");
1969        self.indent -= 1;
1970        self.line("}");
1971        self.indent -= 1;
1972        self.line("}");
1973        self.line("// If no error, result is already on stack");
1974        self.indent -= 1;
1975        self.line("}");
1976        self.blank();
1977    }
1978
1979    fn emit_indexed_zero_or_more_handlers(&mut self) {
1980        // ZeroOrMoreStart
1981        self.line("Work::ZeroOrMoreStart { loop_id, result_base } => {");
1982        self.indent += 1;
1983        self.line("let checkpoint = self.pos;");
1984        self.line("let checkpoint_line = self.line;");
1985        self.line("let checkpoint_column = self.column;");
1986        self.line("let loop_base = self.result_stack.len();");
1987        self.line("self.work_stack.push(Work::ZeroOrMoreLoop { loop_id, result_base, loop_base, iter_base: loop_base, checkpoint, checkpoint_line, checkpoint_column });");
1988        self.line("if let Some(&item) = ZERO_OR_MORE.get(loop_id as usize) {");
1989        self.indent += 1;
1990        self.line("self.dispatch_combref(item, result_base);");
1991        self.indent -= 1;
1992        self.line("}");
1993        self.indent -= 1;
1994        self.line("}");
1995        self.blank();
1996
1997        // ZeroOrMoreLoop
1998        self.line("Work::ZeroOrMoreLoop { loop_id, result_base, loop_base, iter_base, checkpoint, checkpoint_line, checkpoint_column } => {");
1999        self.indent += 1;
2000        self.line("if self.last_error.is_some() {");
2001        self.indent += 1;
2002        self.line("self.last_error = None;");
2003        self.line("self.pos = checkpoint;");
2004        self.line("self.line = checkpoint_line;");
2005        self.line("self.column = checkpoint_column;");
2006        self.line("self.result_stack.truncate(iter_base);");
2007        self.line(
2008            "self.work_stack.push(Work::ZeroOrMoreComplete { loop_id, result_base, loop_base });",
2009        );
2010        self.indent -= 1;
2011        self.line("} else {");
2012        self.indent += 1;
2013        self.line("let checkpoint = self.pos;");
2014        self.line("let checkpoint_line = self.line;");
2015        self.line("let checkpoint_column = self.column;");
2016        self.line("let iter_base = self.result_stack.len();");
2017        self.line("self.work_stack.push(Work::ZeroOrMoreLoop { loop_id, result_base, loop_base, iter_base, checkpoint, checkpoint_line, checkpoint_column });");
2018        self.line("if let Some(&item) = ZERO_OR_MORE.get(loop_id as usize) {");
2019        self.indent += 1;
2020        self.line("self.dispatch_combref(item, result_base);");
2021        self.indent -= 1;
2022        self.line("}");
2023        self.indent -= 1;
2024        self.line("}");
2025        self.indent -= 1;
2026        self.line("}");
2027        self.blank();
2028
2029        // ZeroOrMoreComplete
2030        self.line("Work::ZeroOrMoreComplete { loop_id: _, result_base: _, loop_base } => {");
2031        self.indent += 1;
2032        self.line("let results: Vec<_> = self.result_stack.drain(loop_base..).collect();");
2033        self.line("self.result_stack.push(ParseResult::List(results));");
2034        self.indent -= 1;
2035        self.line("}");
2036        self.blank();
2037    }
2038
2039    fn emit_indexed_one_or_more_handlers(&mut self) {
2040        // OneOrMoreStart
2041        self.line("Work::OneOrMoreStart { loop_id, result_base } => {");
2042        self.indent += 1;
2043        self.line("let checkpoint = self.pos;");
2044        self.line("let checkpoint_line = self.line;");
2045        self.line("let checkpoint_column = self.column;");
2046        self.line("let loop_base = self.result_stack.len();");
2047        self.line("self.work_stack.push(Work::OneOrMoreLoop { loop_id, result_base, loop_base, checkpoint, checkpoint_line, checkpoint_column, count: 0 });");
2048        self.line("if let Some(&item) = ONE_OR_MORE.get(loop_id as usize) {");
2049        self.indent += 1;
2050        self.line("self.dispatch_combref(item, result_base);");
2051        self.indent -= 1;
2052        self.line("}");
2053        self.indent -= 1;
2054        self.line("}");
2055        self.blank();
2056
2057        // OneOrMoreLoop
2058        self.line("Work::OneOrMoreLoop { loop_id, result_base, loop_base, checkpoint, checkpoint_line, checkpoint_column, count } => {");
2059        self.indent += 1;
2060        self.line("if self.last_error.is_some() {");
2061        self.indent += 1;
2062        self.line("if count == 0 {");
2063        self.indent += 1;
2064        self.line("// First item failed - propagate error");
2065        self.line("return Ok(());");
2066        self.indent -= 1;
2067        self.line("}");
2068        self.line("self.last_error = None;");
2069        self.line("self.pos = checkpoint;");
2070        self.line("self.line = checkpoint_line;");
2071        self.line("self.column = checkpoint_column;");
2072        self.line(
2073            "self.work_stack.push(Work::OneOrMoreComplete { loop_id, result_base, loop_base });",
2074        );
2075        self.indent -= 1;
2076        self.line("} else {");
2077        self.indent += 1;
2078        self.line("let checkpoint = self.pos;");
2079        self.line("let checkpoint_line = self.line;");
2080        self.line("let checkpoint_column = self.column;");
2081        self.line("self.work_stack.push(Work::OneOrMoreLoop { loop_id, result_base, loop_base, checkpoint, checkpoint_line, checkpoint_column, count: count + 1 });");
2082        self.line("if let Some(&item) = ONE_OR_MORE.get(loop_id as usize) {");
2083        self.indent += 1;
2084        self.line("self.dispatch_combref(item, result_base);");
2085        self.indent -= 1;
2086        self.line("}");
2087        self.indent -= 1;
2088        self.line("}");
2089        self.indent -= 1;
2090        self.line("}");
2091        self.blank();
2092
2093        // OneOrMoreComplete
2094        self.line("Work::OneOrMoreComplete { loop_id: _, result_base: _, loop_base } => {");
2095        self.indent += 1;
2096        self.line("let results: Vec<_> = self.result_stack.drain(loop_base..).collect();");
2097        self.line("self.result_stack.push(ParseResult::List(results));");
2098        self.indent -= 1;
2099        self.line("}");
2100        self.blank();
2101    }
2102
2103    fn emit_indexed_optional_handlers(&mut self) {
2104        // OptionalStart
2105        self.line("Work::OptionalStart { opt_id, result_base } => {");
2106        self.indent += 1;
2107        self.line("let checkpoint = self.pos;");
2108        self.line("let checkpoint_line = self.line;");
2109        self.line("let checkpoint_column = self.column;");
2110        self.line("let opt_base = self.result_stack.len();");
2111        self.line("self.work_stack.push(Work::OptionalCheck { opt_id, result_base, opt_base, checkpoint, checkpoint_line, checkpoint_column });");
2112        self.line("if let Some(&inner) = OPTIONALS.get(opt_id as usize) {");
2113        self.indent += 1;
2114        self.line("self.dispatch_combref(inner, result_base);");
2115        self.indent -= 1;
2116        self.line("}");
2117        self.indent -= 1;
2118        self.line("}");
2119        self.blank();
2120
2121        // OptionalCheck
2122        self.line("Work::OptionalCheck { opt_id: _, result_base: _, opt_base, checkpoint, checkpoint_line, checkpoint_column } => {");
2123        self.indent += 1;
2124        self.line("if self.last_error.is_some() {");
2125        self.indent += 1;
2126        self.line("self.last_error = None;");
2127        self.line("self.pos = checkpoint;");
2128        self.line("self.line = checkpoint_line;");
2129        self.line("self.column = checkpoint_column;");
2130        self.line("self.result_stack.truncate(opt_base);");
2131        self.line("self.result_stack.push(ParseResult::None);");
2132        self.indent -= 1;
2133        self.line("}");
2134        self.line("// If no error, result is already on stack");
2135        self.indent -= 1;
2136        self.line("}");
2137        self.blank();
2138    }
2139
2140    fn emit_indexed_capture_handlers(&mut self) {
2141        // CaptureStart
2142        self.line("Work::CaptureStart { cap_id, result_base } => {");
2143        self.indent += 1;
2144        self.line("let start_pos = self.pos;");
2145        self.line("let start_line = self.line;");
2146        self.line("let start_column = self.column;");
2147        self.line("let capture_base = self.result_stack.len();");
2148        self.line("self.work_stack.push(Work::CaptureComplete { cap_id, result_base, capture_base, start_pos, start_line, start_column });");
2149        self.line("if let Some(&inner) = CAPTURES.get(cap_id as usize) {");
2150        self.indent += 1;
2151        self.line("self.dispatch_combref(inner, result_base);");
2152        self.indent -= 1;
2153        self.line("}");
2154        self.indent -= 1;
2155        self.line("}");
2156        self.blank();
2157
2158        // CaptureComplete
2159        self.line("Work::CaptureComplete { cap_id: _, result_base: _, capture_base, start_pos, start_line, start_column } => {");
2160        self.indent += 1;
2161        self.line("if self.last_error.is_none() {");
2162        self.indent += 1;
2163        self.line("self.result_stack.truncate(capture_base);");
2164        self.line("let text = self.text_result(start_pos, self.pos);");
2165        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
2166        self.line("self.result_stack.push(ParseResult::Text(text, span));");
2167        self.indent -= 1;
2168        self.line("}");
2169        self.indent -= 1;
2170        self.line("}");
2171        self.blank();
2172    }
2173
2174    fn emit_indexed_lookahead_handlers(&mut self) {
2175        // NotFollowedByStart
2176        self.line("Work::NotFollowedByStart { look_id, result_base } => {");
2177        self.indent += 1;
2178        self.line("let checkpoint = self.pos;");
2179        self.line("let checkpoint_line = self.line;");
2180        self.line("let checkpoint_column = self.column;");
2181        self.line("let look_base = self.result_stack.len();");
2182        self.line("self.work_stack.push(Work::NotFollowedByCheck { look_id, result_base, look_base, checkpoint, checkpoint_line, checkpoint_column });");
2183        self.line("if let Some(&inner) = NOT_FOLLOWED_BY.get(look_id as usize) {");
2184        self.indent += 1;
2185        self.line("self.dispatch_combref(inner, result_base);");
2186        self.indent -= 1;
2187        self.line("}");
2188        self.indent -= 1;
2189        self.line("}");
2190        self.blank();
2191
2192        // NotFollowedByCheck
2193        self.line("Work::NotFollowedByCheck { look_id: _, result_base: _, look_base, checkpoint, checkpoint_line, checkpoint_column } => {");
2194        self.indent += 1;
2195        self.line("self.result_stack.truncate(look_base);");
2196        self.line("self.pos = checkpoint;");
2197        self.line("self.line = checkpoint_line;");
2198        self.line("self.column = checkpoint_column;");
2199        self.line("if self.last_error.is_some() {");
2200        self.indent += 1;
2201        self.line("// Inner failed = negative lookahead succeeded");
2202        self.line("self.last_error = None;");
2203        self.line("self.result_stack.push(ParseResult::None);");
2204        self.indent -= 1;
2205        self.line("} else {");
2206        self.indent += 1;
2207        self.line("// Inner succeeded = negative lookahead failed");
2208        self.line(
2209            "self.last_error = Some(self.make_error(\"unexpected match in not-followed-by\"));",
2210        );
2211        self.indent -= 1;
2212        self.line("}");
2213        self.indent -= 1;
2214        self.line("}");
2215        self.blank();
2216
2217        // FollowedByStart
2218        self.line("Work::FollowedByStart { look_id, result_base } => {");
2219        self.indent += 1;
2220        self.line("let checkpoint = self.pos;");
2221        self.line("let checkpoint_line = self.line;");
2222        self.line("let checkpoint_column = self.column;");
2223        self.line("let look_base = self.result_stack.len();");
2224        self.line("self.work_stack.push(Work::FollowedByCheck { look_id, result_base, look_base, checkpoint, checkpoint_line, checkpoint_column });");
2225        self.line("if let Some(&inner) = FOLLOWED_BY.get(look_id as usize) {");
2226        self.indent += 1;
2227        self.line("self.dispatch_combref(inner, result_base);");
2228        self.indent -= 1;
2229        self.line("}");
2230        self.indent -= 1;
2231        self.line("}");
2232        self.blank();
2233
2234        // FollowedByCheck
2235        self.line("Work::FollowedByCheck { look_id: _, result_base: _, look_base, checkpoint, checkpoint_line, checkpoint_column } => {");
2236        self.indent += 1;
2237        self.line("self.result_stack.truncate(look_base);");
2238        self.line("self.pos = checkpoint;");
2239        self.line("self.line = checkpoint_line;");
2240        self.line("self.column = checkpoint_column;");
2241        self.line("if self.last_error.is_none() {");
2242        self.indent += 1;
2243        self.line("// Inner succeeded = positive lookahead succeeded");
2244        self.line("self.result_stack.push(ParseResult::None);");
2245        self.indent -= 1;
2246        self.line("}");
2247        self.line("// If error, propagate it");
2248        self.indent -= 1;
2249        self.line("}");
2250        self.blank();
2251    }
2252
2253    fn emit_indexed_skip_handlers(&mut self) {
2254        // SkipStart
2255        self.line("Work::SkipStart { skip_id, result_base } => {");
2256        self.indent += 1;
2257        self.line("let skip_base = self.result_stack.len();");
2258        self.line("self.work_stack.push(Work::SkipComplete { skip_id, result_base, skip_base });");
2259        self.line("if let Some(&inner) = SKIPS.get(skip_id as usize) {");
2260        self.indent += 1;
2261        self.line("self.dispatch_combref(inner, result_base);");
2262        self.indent -= 1;
2263        self.line("}");
2264        self.indent -= 1;
2265        self.line("}");
2266        self.blank();
2267
2268        // SkipComplete
2269        self.line("Work::SkipComplete { skip_id: _, result_base: _, skip_base } => {");
2270        self.indent += 1;
2271        self.line("if self.last_error.is_none() {");
2272        self.indent += 1;
2273        self.line("self.result_stack.truncate(skip_base);");
2274        self.line("self.result_stack.push(ParseResult::None);");
2275        self.indent -= 1;
2276        self.line("}");
2277        self.indent -= 1;
2278        self.line("}");
2279        self.blank();
2280    }
2281
2282    fn emit_indexed_separated_by_handlers(&mut self) {
2283        // SepByStart
2284        self.line("Work::SepByStart { sepby_id, result_base } => {");
2285        self.indent += 1;
2286        self.line("if let Some(&(item, _sep, _trailing)) = SEPARATED_BY.get(sepby_id as usize) {");
2287        self.indent += 1;
2288        self.line("let list_base = self.result_stack.len();");
2289        self.line("let checkpoint = self.pos;");
2290        self.line("let checkpoint_line = self.line;");
2291        self.line("let checkpoint_column = self.column;");
2292        self.line("self.work_stack.push(Work::SepBySep { sepby_id, result_base, list_base, checkpoint, checkpoint_line, checkpoint_column });");
2293        self.line("self.dispatch_combref(item, result_base);");
2294        self.indent -= 1;
2295        self.line("}");
2296        self.indent -= 1;
2297        self.line("}");
2298        self.blank();
2299
2300        // SepBySep
2301        self.line("Work::SepBySep { sepby_id, result_base, list_base, checkpoint, checkpoint_line, checkpoint_column } => {");
2302        self.indent += 1;
2303        self.line("if self.last_error.is_some() {");
2304        self.indent += 1;
2305        self.line("self.last_error = None;");
2306        self.line("self.pos = checkpoint;");
2307        self.line("self.line = checkpoint_line;");
2308        self.line("self.column = checkpoint_column;");
2309        self.line(
2310            "self.work_stack.push(Work::SepByComplete { sepby_id, result_base, list_base });",
2311        );
2312        self.indent -= 1;
2313        self.line(
2314            "} else if let Some(&(_item, sep, _trailing)) = SEPARATED_BY.get(sepby_id as usize) {",
2315        );
2316        self.indent += 1;
2317        self.line("let checkpoint = self.pos;");
2318        self.line("let checkpoint_line = self.line;");
2319        self.line("let checkpoint_column = self.column;");
2320        self.line("self.work_stack.push(Work::SepByItem { sepby_id, result_base, list_base, checkpoint, checkpoint_line, checkpoint_column });");
2321        self.line("self.dispatch_combref(sep, result_base);");
2322        self.indent -= 1;
2323        self.line("}");
2324        self.indent -= 1;
2325        self.line("}");
2326        self.blank();
2327
2328        // SepByItem
2329        self.line("Work::SepByItem { sepby_id, result_base, list_base, checkpoint, checkpoint_line, checkpoint_column } => {");
2330        self.indent += 1;
2331        self.line("if self.last_error.is_some() {");
2332        self.indent += 1;
2333        self.line("self.last_error = None;");
2334        self.line("self.pos = checkpoint;");
2335        self.line("self.line = checkpoint_line;");
2336        self.line("self.column = checkpoint_column;");
2337        self.line("// Separator failed - no separator result was pushed, so nothing to pop");
2338        self.line(
2339            "self.work_stack.push(Work::SepByComplete { sepby_id, result_base, list_base });",
2340        );
2341        self.indent -= 1;
2342        self.line(
2343            "} else if let Some(&(item, _sep, _trailing)) = SEPARATED_BY.get(sepby_id as usize) {",
2344        );
2345        self.indent += 1;
2346        self.line("// Pop separator result (we don't keep it)");
2347        self.line("self.result_stack.pop();");
2348        self.line("let checkpoint = self.pos;");
2349        self.line("let checkpoint_line = self.line;");
2350        self.line("let checkpoint_column = self.column;");
2351        self.line("self.work_stack.push(Work::SepBySep { sepby_id, result_base, list_base, checkpoint, checkpoint_line, checkpoint_column });");
2352        self.line("self.dispatch_combref(item, result_base);");
2353        self.indent -= 1;
2354        self.line("}");
2355        self.indent -= 1;
2356        self.line("}");
2357        self.blank();
2358
2359        // SepByComplete
2360        self.line("Work::SepByComplete { sepby_id: _, result_base: _, list_base } => {");
2361        self.indent += 1;
2362        self.line("let results: Vec<_> = self.result_stack.drain(list_base..).collect();");
2363        self.line("self.result_stack.push(ParseResult::List(results));");
2364        self.indent -= 1;
2365        self.line("}");
2366        self.blank();
2367    }
2368
2369    fn emit_indexed_mapped_handlers(&mut self) {
2370        // MappedStart
2371        self.line("Work::MappedStart { map_id, result_base } => {");
2372        self.indent += 1;
2373        self.line("let start_pos = self.pos;");
2374        self.line("let start_line = self.line;");
2375        self.line("let start_column = self.column;");
2376        self.line("let map_base = self.result_stack.len();");
2377        self.line("self.work_stack.push(Work::MappedApply { map_id, result_base, map_base, start_pos, start_line, start_column });");
2378        self.line("if let Some(&(inner, _)) = MAPPED.get(map_id as usize) {");
2379        self.indent += 1;
2380        self.line("self.dispatch_combref(inner, result_base);");
2381        self.indent -= 1;
2382        self.line("}");
2383        self.indent -= 1;
2384        self.line("}");
2385        self.blank();
2386
2387        // MappedApply - apply the mapping function
2388        self.line("Work::MappedApply { map_id, result_base, map_base, start_pos, start_line, start_column } => {");
2389        self.indent += 1;
2390        self.line("if self.last_error.is_some() {");
2391        self.indent += 1;
2392        self.line("// Inner combinator failed, propagate error");
2393        self.indent -= 1;
2394        self.line("} else if let Some(inner_result) = self.result_stack.get(map_base).cloned() {");
2395        self.indent += 1;
2396        self.line("// Remove inner result and apply mapping");
2397        self.line("self.result_stack.truncate(map_base);");
2398        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
2399        self.line("let mapped = self.apply_mapping(map_id, inner_result, span);");
2400        self.line("match mapped {");
2401        self.indent += 1;
2402        self.line("Ok(result) => self.result_stack.push(result),");
2403        self.line("Err(e) => self.last_error = Some(e),");
2404        self.indent -= 1;
2405        self.line("}");
2406        self.indent -= 1;
2407        self.line("}");
2408        self.indent -= 1;
2409        self.line("}");
2410        self.blank();
2411    }
2412
2413    fn emit_indexed_memoize_handlers(&mut self) {
2414        // MemoStart
2415        self.line("Work::MemoStart { memo_id, result_base } => {");
2416        self.indent += 1;
2417        self.line("if let Some(&(memo_key, inner)) = MEMOIZED.get(memo_id as usize) {");
2418        self.indent += 1;
2419        self.line("let key = (memo_key, self.pos);");
2420        self.line("if let Some(cached) = self.memo.get(&key) {");
2421        self.indent += 1;
2422        self.line("if let Some((result, end_pos, end_line, end_column)) = cached.clone() {");
2423        self.indent += 1;
2424        self.line("self.pos = end_pos;");
2425        self.line("self.line = end_line;");
2426        self.line("self.column = end_column;");
2427        self.line("self.result_stack.push(result);");
2428        self.indent -= 1;
2429        self.line("} else {");
2430        self.indent += 1;
2431        self.line("self.last_error = Some(self.make_error(\"memoized failure\"));");
2432        self.indent -= 1;
2433        self.line("}");
2434        self.indent -= 1;
2435        self.line("} else {");
2436        self.indent += 1;
2437        self.line("let start_pos = self.pos;");
2438        self.line("let inner_base = self.result_stack.len();");
2439        self.line("self.work_stack.push(Work::MemoComplete { memo_id, result_base, start_pos, inner_base });");
2440        self.line("self.dispatch_combref(inner, result_base);");
2441        self.indent -= 1;
2442        self.line("}");
2443        self.indent -= 1;
2444        self.line("}");
2445        self.indent -= 1;
2446        self.line("}");
2447        self.blank();
2448
2449        // MemoComplete
2450        self.line("Work::MemoComplete { memo_id, result_base: _, start_pos, inner_base } => {");
2451        self.indent += 1;
2452        self.line("if let Some(&(memo_key, _)) = MEMOIZED.get(memo_id as usize) {");
2453        self.indent += 1;
2454        self.line("let key = (memo_key, start_pos);");
2455        self.line("if self.last_error.is_some() {");
2456        self.indent += 1;
2457        self.line("self.memo.insert(key, None);");
2458        self.indent -= 1;
2459        self.line("} else if let Some(result) = self.result_stack.get(inner_base).cloned() {");
2460        self.indent += 1;
2461        self.line("self.memo.insert(key, Some((result, self.pos, self.line, self.column)));");
2462        self.indent -= 1;
2463        self.line("}");
2464        self.indent -= 1;
2465        self.line("}");
2466        self.indent -= 1;
2467        self.line("}");
2468        self.blank();
2469    }
2470
2471    fn emit_indexed_terminal_handlers(&mut self) {
2472        // Literal
2473        self.line("Work::Literal { lit_id, result_base: _ } => {");
2474        self.indent += 1;
2475        self.line("if let Some(&lit) = LITERALS.get(lit_id as usize) {");
2476        self.indent += 1;
2477        self.line("if !self.match_literal(lit) {");
2478        self.indent += 1;
2479        self.line("self.last_error = Some(self.make_error(&format!(\"expected '{}'\", lit)));");
2480        self.indent -= 1;
2481        self.line("} else {");
2482        self.indent += 1;
2483        self.line("self.result_stack.push(ParseResult::None);");
2484        self.indent -= 1;
2485        self.line("}");
2486        self.indent -= 1;
2487        self.line("}");
2488        self.indent -= 1;
2489        self.line("}");
2490        self.blank();
2491
2492        // CharClass
2493        self.line("Work::CharClass { class, result_base: _ } => {");
2494        self.indent += 1;
2495        self.line("let matched = match class {");
2496        self.indent += 1;
2497        self.line("0 => self.match_char_class(|c: char| c.is_ascii_digit()),");
2498        self.line("1 => self.match_char_class(|c: char| c.is_ascii_hexdigit()),");
2499        self.line("2 => self.match_char_class(|c: char| c.is_ascii_alphabetic()),");
2500        self.line("3 => self.match_char_class(|c: char| c.is_ascii_alphanumeric()),");
2501        self.line("4 => self.match_char_class(|c: char| matches!(c, ' ' | '\\t' | '\\x0B' | '\\x0C' | '\\r' | '\\n' | '\\u{00A0}' | '\\u{FEFF}' | '\\u{2028}' | '\\u{2029}') || c.is_whitespace()),");
2502        self.line("5 => self.match_char_class(|c: char| c.is_ascii_alphabetic() || c == '_' || c == '$'),");
2503        self.line("6 => self.match_char_class(|c: char| c.is_ascii_alphanumeric() || c == '_' || c == '$'),");
2504        self.line("_ => None,");
2505        self.indent -= 1;
2506        self.line("};");
2507        self.line("if matched.is_none() {");
2508        self.indent += 1;
2509        self.line("self.last_error = Some(self.make_error(\"expected character class\"));");
2510        self.indent -= 1;
2511        self.line("} else {");
2512        self.indent += 1;
2513        self.line("self.result_stack.push(ParseResult::None);");
2514        self.indent -= 1;
2515        self.line("}");
2516        self.indent -= 1;
2517        self.line("}");
2518        self.blank();
2519
2520        // CharRange
2521        self.line("Work::CharRange { from, to, result_base: _ } => {");
2522        self.indent += 1;
2523        self.line("if let Some(c) = self.current_char() {");
2524        self.indent += 1;
2525        self.line("if c >= from && c <= to {");
2526        self.indent += 1;
2527        self.line("self.advance();");
2528        self.line("self.result_stack.push(ParseResult::None);");
2529        self.indent -= 1;
2530        self.line("} else {");
2531        self.indent += 1;
2532        self.line("self.last_error = Some(self.make_error(&format!(\"expected char in range '{}'..='{}'\", from, to)));");
2533        self.indent -= 1;
2534        self.line("}");
2535        self.indent -= 1;
2536        self.line("} else {");
2537        self.indent += 1;
2538        self.line("self.last_error = Some(self.make_error(\"unexpected end of input\"));");
2539        self.indent -= 1;
2540        self.line("}");
2541        self.indent -= 1;
2542        self.line("}");
2543        self.blank();
2544
2545        // Char
2546        self.line("Work::Char { ch, result_base: _ } => {");
2547        self.indent += 1;
2548        self.line("if self.current_char() == Some(ch) {");
2549        self.indent += 1;
2550        self.line("self.advance();");
2551        self.line("self.result_stack.push(ParseResult::None);");
2552        self.indent -= 1;
2553        self.line("} else {");
2554        self.indent += 1;
2555        self.line("self.last_error = Some(self.make_error(&format!(\"expected '{}'\", ch)));");
2556        self.indent -= 1;
2557        self.line("}");
2558        self.indent -= 1;
2559        self.line("}");
2560        self.blank();
2561
2562        // AnyChar
2563        self.line("Work::AnyChar { result_base: _ } => {");
2564        self.indent += 1;
2565        self.line("if self.current_char().is_some() {");
2566        self.indent += 1;
2567        self.line("self.advance();");
2568        self.line("self.result_stack.push(ParseResult::None);");
2569        self.indent -= 1;
2570        self.line("} else {");
2571        self.indent += 1;
2572        self.line("self.last_error = Some(self.make_error(\"unexpected end of input\"));");
2573        self.indent -= 1;
2574        self.line("}");
2575        self.indent -= 1;
2576        self.line("}");
2577        self.blank();
2578    }
2579
2580    fn emit_indexed_pratt_handlers(&mut self) {
2581        if self.index.pratts.is_empty() {
2582            // No Pratt parsers - add unreachable handlers for all Pratt work variants
2583            self.line("// No Pratt parsers in this grammar - unreachable handlers");
2584            self.line("Work::PrattStart { .. } => {}");
2585            self.line("Work::PrattParseOperand { .. } => {}");
2586            self.line("Work::PrattAfterPrefix { .. } => {}");
2587            self.line("Work::PrattAfterPrefixLeadingRule { .. } => {}");
2588            self.line("Work::PrattCheckPostfix { .. } => {}");
2589            self.line("Work::PrattAfterPostfixSimple { .. } => {}");
2590            self.line("Work::PrattPostfixCallArg { .. } => {}");
2591            self.line("Work::PrattPostfixCallSep { .. } => {}");
2592            self.line("Work::PrattAfterPostfixCall { .. } => {}");
2593            self.line("Work::PrattAfterPostfixIndex { .. } => {}");
2594            self.line("Work::PrattAfterPostfixMember { .. } => {}");
2595            self.line("Work::PrattAfterPostfixRule { .. } => {}");
2596            self.line("Work::PrattAfterOperand { .. } => {}");
2597            self.line("Work::PrattAfterInfix { .. } => {}");
2598            self.line("Work::PrattAfterInfixLeadingRule { .. } => {}");
2599            self.line("Work::PrattAfterTernaryFirst { .. } => {}");
2600            self.line("Work::PrattAfterTernarySecond { .. } => {}");
2601            self.blank();
2602            return;
2603        }
2604
2605        self.line("// === Pratt parsing handlers ===");
2606        self.blank();
2607
2608        // PrattStart - begin Pratt parsing with min precedence 0
2609        self.line("Work::PrattStart { pratt_id, result_base } => {");
2610        self.indent += 1;
2611        self.line("let start_pos = self.pos;");
2612        self.line("let start_line = self.line;");
2613        self.line("let start_column = self.column;");
2614        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base, min_prec: 0, start_pos, start_line, start_column });");
2615        self.indent -= 1;
2616        self.line("}");
2617        self.blank();
2618
2619        // PrattParseOperand - try prefix operators, then parse operand
2620        self.emit_pratt_parse_operand_handler();
2621
2622        // PrattAfterPrefix - apply prefix mapping, continue loop
2623        self.emit_pratt_after_prefix_handler();
2624
2625        // PrattAfterPrefixLeadingRule
2626        self.emit_pratt_after_prefix_leading_rule_handler();
2627
2628        // PrattCheckPostfix
2629        self.emit_pratt_check_postfix_handler();
2630
2631        // PrattAfterPostfixSimple
2632        self.emit_pratt_after_postfix_simple_handler();
2633
2634        // PrattPostfixCallArg
2635        self.emit_pratt_postfix_call_arg_handler();
2636
2637        // PrattPostfixCallSep
2638        self.emit_pratt_postfix_call_sep_handler();
2639
2640        // PrattAfterPostfixCall
2641        self.emit_pratt_after_postfix_call_handler();
2642
2643        // PrattAfterPostfixIndex
2644        self.emit_pratt_after_postfix_index_handler();
2645
2646        // PrattAfterPostfixMember
2647        self.emit_pratt_after_postfix_member_handler();
2648
2649        // PrattAfterPostfixRule
2650        self.emit_pratt_after_postfix_rule_handler();
2651
2652        // PrattAfterOperand - check for infix operators
2653        self.emit_pratt_after_operand_handler();
2654
2655        // PrattAfterInfix
2656        self.emit_pratt_after_infix_handler();
2657
2658        // PrattAfterInfixLeadingRule
2659        self.emit_pratt_after_infix_leading_rule_handler();
2660
2661        // PrattAfterTernaryFirst
2662        self.emit_pratt_after_ternary_first_handler();
2663
2664        // PrattAfterTernarySecond
2665        self.emit_pratt_after_ternary_second_handler();
2666    }
2667
2668    fn emit_pratt_parse_operand_handler(&mut self) {
2669        self.line("Work::PrattParseOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column } => {");
2670        self.indent += 1;
2671        self.line("let pratt = &PRATTS[pratt_id as usize];");
2672        self.line("let prefix_checkpoint = self.pos;");
2673        self.line("let prefix_checkpoint_line = self.line;");
2674        self.line("let prefix_checkpoint_column = self.column;");
2675        self.line("let mut prefix_matched = false;");
2676        self.blank();
2677
2678        // Try prefix operators without leading rules
2679        self.line("// Try prefix operators without leading rules");
2680        self.line("for (op_idx, prefix_op) in pratt.prefix_ops.iter().enumerate() {");
2681        self.indent += 1;
2682        self.line("if prefix_matched { break; }");
2683        self.line("if prefix_op.leading_rule.is_some() { continue; }");
2684        self.line("if prefix_op.literal.is_empty() { continue; }");
2685        self.blank();
2686        self.line("// Check not_followed_by patterns");
2687        self.line("let mut can_match = self.input.get(self.pos..).unwrap_or(\"\").starts_with(prefix_op.literal);");
2688        self.line("if can_match {");
2689        self.indent += 1;
2690        self.line("for nfb in prefix_op.not_followed_by {");
2691        self.indent += 1;
2692        self.line("let combined = format!(\"{}{}\", prefix_op.literal, nfb);");
2693        self.line("if self.input.get(self.pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
2694        self.indent -= 1;
2695        self.line("}");
2696        self.indent -= 1;
2697        self.line("}");
2698        self.blank();
2699        self.line("if can_match {");
2700        self.indent += 1;
2701        self.line("self.pos += prefix_op.literal.len();");
2702        self.line("self.column += prefix_op.literal.len() as u32;");
2703        self.blank();
2704        self.line("// Keyword boundary check");
2705        self.line("if prefix_op.is_keyword {");
2706        self.indent += 1;
2707        self.line("let boundary_ok = self.current_char().map_or(true, |c| !(c.is_ascii_alphanumeric() || c == '_' || c == '$'));");
2708        self.line("if !boundary_ok {");
2709        self.indent += 1;
2710        self.line("self.pos = prefix_checkpoint;");
2711        self.line("self.line = prefix_checkpoint_line;");
2712        self.line("self.column = prefix_checkpoint_column;");
2713        self.line("continue;");
2714        self.indent -= 1;
2715        self.line("}");
2716        self.indent -= 1;
2717        self.line("}");
2718        self.blank();
2719        self.line("prefix_matched = true;");
2720        self.line("self.work_stack.push(Work::PrattAfterPrefix { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
2721        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: prefix_op.precedence, start_pos: self.pos, start_line: self.line, start_column: self.column });");
2722        self.indent -= 1;
2723        self.line("}");
2724        self.indent -= 1;
2725        self.line("}");
2726        self.blank();
2727
2728        // Check for prefix operators with leading rules
2729        self.line("// Try prefix operators with leading rules");
2730        self.line("if !prefix_matched && pratt.has_prefix_with_leading {");
2731        self.indent += 1;
2732        self.line("// Find first leading rule and parse it");
2733        self.line(
2734            "if let Some(rule_id) = pratt.prefix_ops.iter().find_map(|op| op.leading_rule) {",
2735        );
2736        self.indent += 1;
2737        self.line("self.work_stack.push(Work::PrattAfterPrefixLeadingRule { pratt_id, result_base, min_prec, checkpoint: prefix_checkpoint, checkpoint_line: prefix_checkpoint_line, checkpoint_column: prefix_checkpoint_column, start_pos, start_line, start_column });");
2738        self.line(
2739            "self.work_stack.push(Work::Rule { rule_id, result_base: self.result_stack.len() });",
2740        );
2741        self.indent -= 1;
2742        self.line("}");
2743        self.indent -= 1;
2744        self.line("} else if !prefix_matched {");
2745        self.indent += 1;
2746        // No prefix matched - parse operand directly
2747        self.line("// No prefix - parse operand directly");
2748        self.line("if !pratt.postfix_ops.is_empty() {");
2749        self.indent += 1;
2750        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2751        self.indent -= 1;
2752        self.line("} else {");
2753        self.indent += 1;
2754        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2755        self.indent -= 1;
2756        self.line("}");
2757        self.line("if let Some(operand_ref) = pratt.operand {");
2758        self.indent += 1;
2759        self.line("self.dispatch_combref(operand_ref, result_base);");
2760        self.indent -= 1;
2761        self.line("}");
2762        self.indent -= 1;
2763        self.line("}");
2764        self.indent -= 1;
2765        self.line("}");
2766        self.blank();
2767    }
2768
2769    fn emit_pratt_after_prefix_handler(&mut self) {
2770        self.line("Work::PrattAfterPrefix { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
2771        self.indent += 1;
2772        self.line("if self.last_error.is_some() { return Ok(()); }");
2773        self.line("let operand = self.result_stack.pop().unwrap_or(ParseResult::None);");
2774        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
2775        self.blank();
2776
2777        // Generate match on (pratt_id, op_idx) to call mapping
2778        self.emit_prefix_mapping_dispatch();
2779
2780        self.line("// Continue with postfix/infix loop");
2781        self.line("let pratt = &PRATTS[pratt_id as usize];");
2782        self.line("if !pratt.postfix_ops.is_empty() {");
2783        self.indent += 1;
2784        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2785        self.indent -= 1;
2786        self.line("} else {");
2787        self.indent += 1;
2788        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2789        self.indent -= 1;
2790        self.line("}");
2791        self.indent -= 1;
2792        self.line("}");
2793        self.blank();
2794    }
2795
2796    fn emit_prefix_mapping_dispatch(&mut self) {
2797        // Pre-collect mapping arms to avoid borrow conflicts
2798        let mut arms: Vec<(usize, usize, String)> = Vec::new();
2799        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
2800            for (op_idx, prefix_op) in pratt.prefix_ops.iter().enumerate() {
2801                let mapping = self.index.mappings[prefix_op.mapping_idx].clone();
2802                arms.push((pratt_idx, op_idx, mapping));
2803            }
2804        }
2805
2806        self.line("match (pratt_id, op_idx) {");
2807        self.indent += 1;
2808
2809        for (pratt_idx, op_idx, mapping) in arms {
2810            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
2811            self.indent += 1;
2812            self.line(&format!("let mapping_fn = {};", mapping));
2813            self.line("match mapping_fn(operand, span) {");
2814            self.indent += 1;
2815            self.line("Ok(mapped) => self.result_stack.push(mapped),");
2816            self.line("Err(e) => self.last_error = Some(e),");
2817            self.indent -= 1;
2818            self.line("}");
2819            self.indent -= 1;
2820            self.line("}");
2821        }
2822
2823        self.line("_ => { self.result_stack.push(operand); }");
2824        self.indent -= 1;
2825        self.line("}");
2826    }
2827
2828    fn emit_pratt_after_prefix_leading_rule_handler(&mut self) {
2829        self.line("Work::PrattAfterPrefixLeadingRule { pratt_id, result_base, min_prec, checkpoint, checkpoint_line, checkpoint_column, start_pos, start_line, start_column } => {");
2830        self.indent += 1;
2831        self.line("let _ = self.result_stack.pop(); // Discard leading rule result");
2832        self.line("self.last_error = None;");
2833        self.line("let pratt = &PRATTS[pratt_id as usize];");
2834        self.line("let mut prefix_matched = false;");
2835        self.blank();
2836
2837        self.line("// Try prefix operators with leading rules");
2838        self.line("for (op_idx, prefix_op) in pratt.prefix_ops.iter().enumerate() {");
2839        self.indent += 1;
2840        self.line("if prefix_matched { break; }");
2841        self.line("if prefix_op.leading_rule.is_none() { continue; }");
2842        self.line("if prefix_op.literal.is_empty() { continue; }");
2843        self.blank();
2844        self.line("let mut can_match = self.input.get(self.pos..).unwrap_or(\"\").starts_with(prefix_op.literal);");
2845        self.line("if can_match {");
2846        self.indent += 1;
2847        self.line("for nfb in prefix_op.not_followed_by {");
2848        self.indent += 1;
2849        self.line("let combined = format!(\"{}{}\", prefix_op.literal, nfb);");
2850        self.line("if self.input.get(self.pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
2851        self.indent -= 1;
2852        self.line("}");
2853        self.indent -= 1;
2854        self.line("}");
2855        self.blank();
2856        self.line("if can_match {");
2857        self.indent += 1;
2858        self.line("self.pos += prefix_op.literal.len();");
2859        self.line("self.column += prefix_op.literal.len() as u32;");
2860        self.line("if prefix_op.is_keyword {");
2861        self.indent += 1;
2862        self.line("if !self.current_char().map_or(true, |c| !(c.is_ascii_alphanumeric() || c == '_' || c == '$')) {");
2863        self.indent += 1;
2864        self.line("self.pos = checkpoint;");
2865        self.line("self.line = checkpoint_line;");
2866        self.line("self.column = checkpoint_column;");
2867        self.line("continue;");
2868        self.indent -= 1;
2869        self.line("}");
2870        self.indent -= 1;
2871        self.line("}");
2872        self.line("prefix_matched = true;");
2873        self.line("self.work_stack.push(Work::PrattAfterPrefix { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
2874        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: prefix_op.precedence, start_pos: self.pos, start_line: self.line, start_column: self.column });");
2875        self.indent -= 1;
2876        self.line("}");
2877        self.indent -= 1;
2878        self.line("}");
2879        self.blank();
2880
2881        self.line("if !prefix_matched {");
2882        self.indent += 1;
2883        self.line("self.pos = checkpoint;");
2884        self.line("self.line = checkpoint_line;");
2885        self.line("self.column = checkpoint_column;");
2886        self.line("if !pratt.postfix_ops.is_empty() {");
2887        self.indent += 1;
2888        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2889        self.indent -= 1;
2890        self.line("} else {");
2891        self.indent += 1;
2892        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
2893        self.indent -= 1;
2894        self.line("}");
2895        self.line("if let Some(operand_ref) = pratt.operand {");
2896        self.indent += 1;
2897        self.line("self.dispatch_combref(operand_ref, result_base);");
2898        self.indent -= 1;
2899        self.line("}");
2900        self.indent -= 1;
2901        self.line("}");
2902        self.indent -= 1;
2903        self.line("}");
2904        self.blank();
2905    }
2906
2907    fn emit_pratt_check_postfix_handler(&mut self) {
2908        self.line("Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column } => {");
2909        self.indent += 1;
2910        self.line("if self.last_error.is_some() { return Ok(()); }");
2911        self.line("let pratt = &PRATTS[pratt_id as usize];");
2912        self.line("let postfix_checkpoint = self.pos;");
2913        self.line("let mut postfix_matched = false;");
2914        self.blank();
2915
2916        self.line("for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {");
2917        self.indent += 1;
2918        self.line("if postfix_matched { break; }");
2919        self.line("if postfix_op.precedence < min_prec { continue; }");
2920        self.blank();
2921        self.line("match postfix_op.kind {");
2922        self.indent += 1;
2923
2924        // Simple postfix
2925        self.line("PostfixKind::Simple => {");
2926        self.indent += 1;
2927        self.line("if postfix_op.open_lit.is_empty() { continue; }");
2928        self.line("let mut can_match = self.input.get(self.pos..).unwrap_or(\"\").starts_with(postfix_op.open_lit);");
2929        self.line("if can_match {");
2930        self.indent += 1;
2931        self.line("for nfb in postfix_op.not_followed_by {");
2932        self.indent += 1;
2933        self.line("let combined = format!(\"{}{}\", postfix_op.open_lit, nfb);");
2934        self.line("if self.input.get(self.pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
2935        self.indent -= 1;
2936        self.line("}");
2937        self.indent -= 1;
2938        self.line("}");
2939        self.line("if can_match {");
2940        self.indent += 1;
2941        self.line("self.pos += postfix_op.open_lit.len();");
2942        self.line("self.column += postfix_op.open_lit.len() as u32;");
2943        self.line("postfix_matched = true;");
2944        self.line("self.work_stack.push(Work::PrattAfterPostfixSimple { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
2945        self.indent -= 1;
2946        self.line("}");
2947        self.indent -= 1;
2948        self.line("}");
2949
2950        // Call postfix
2951        self.line("PostfixKind::Call => {");
2952        self.indent += 1;
2953        self.line("if self.try_consume(postfix_op.open_lit) {");
2954        self.indent += 1;
2955        self.line("postfix_matched = true;");
2956        self.line("let args_base = self.result_stack.len();");
2957        self.line("self.work_stack.push(Work::PrattPostfixCallArg { pratt_id, result_base, min_prec, op_idx: op_idx as u8, args_base, start_pos, start_line, start_column });");
2958        self.indent -= 1;
2959        self.line("}");
2960        self.indent -= 1;
2961        self.line("}");
2962
2963        // Index postfix
2964        self.line("PostfixKind::Index => {");
2965        self.indent += 1;
2966        self.line("if self.try_consume(postfix_op.open_lit) {");
2967        self.indent += 1;
2968        self.line("postfix_matched = true;");
2969        self.line("self.work_stack.push(Work::PrattAfterPostfixIndex { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
2970        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: 0, start_pos: self.pos, start_line: self.line, start_column: self.column });");
2971        self.indent -= 1;
2972        self.line("}");
2973        self.indent -= 1;
2974        self.line("}");
2975
2976        // Member postfix
2977        self.line("PostfixKind::Member => {");
2978        self.indent += 1;
2979        self.line("if postfix_op.open_lit.is_empty() { continue; }");
2980        self.line("let mut can_match = self.input.get(self.pos..).unwrap_or(\"\").starts_with(postfix_op.open_lit);");
2981        self.line("if can_match {");
2982        self.indent += 1;
2983        self.line("for nfb in postfix_op.not_followed_by {");
2984        self.indent += 1;
2985        self.line("let combined = format!(\"{}{}\", postfix_op.open_lit, nfb);");
2986        self.line("if self.input.get(self.pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
2987        self.indent -= 1;
2988        self.line("}");
2989        self.indent -= 1;
2990        self.line("}");
2991        self.line("if can_match {");
2992        self.indent += 1;
2993        self.line("self.pos += postfix_op.open_lit.len();");
2994        self.line("self.column += postfix_op.open_lit.len() as u32;");
2995        self.line("postfix_matched = true;");
2996        self.line("self.work_stack.push(Work::PrattAfterPostfixMember { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
2997        self.indent -= 1;
2998        self.line("}");
2999        self.indent -= 1;
3000        self.line("}");
3001
3002        // Rule postfix
3003        self.line("PostfixKind::Rule => {");
3004        self.indent += 1;
3005        self.line("if let Some(rule_id) = postfix_op.rule_name_id {");
3006        self.indent += 1;
3007        self.line("// For rule-based postfix like tagged templates, check start char");
3008        self.line("if self.current_char() == Some('`') {");
3009        self.indent += 1;
3010        self.line("postfix_matched = true;");
3011        self.line("self.work_stack.push(Work::PrattAfterPostfixRule { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
3012        self.line(
3013            "self.work_stack.push(Work::Rule { rule_id, result_base: self.result_stack.len() });",
3014        );
3015        self.indent -= 1;
3016        self.line("}");
3017        self.indent -= 1;
3018        self.line("}");
3019        self.indent -= 1;
3020        self.line("}");
3021
3022        self.indent -= 1;
3023        self.line("}");
3024        self.indent -= 1;
3025        self.line("}");
3026        self.blank();
3027
3028        self.line("if !postfix_matched {");
3029        self.indent += 1;
3030        self.line("self.pos = postfix_checkpoint;");
3031        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3032        self.indent -= 1;
3033        self.line("}");
3034        self.indent -= 1;
3035        self.line("}");
3036        self.blank();
3037    }
3038
3039    fn emit_pratt_after_postfix_simple_handler(&mut self) {
3040        self.line("Work::PrattAfterPostfixSimple { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
3041        self.indent += 1;
3042        self.line("let operand = self.result_stack.pop().unwrap_or(ParseResult::None);");
3043        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3044        self.emit_postfix_simple_mapping_dispatch();
3045        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3046        self.indent -= 1;
3047        self.line("}");
3048        self.blank();
3049    }
3050
3051    fn emit_postfix_simple_mapping_dispatch(&mut self) {
3052        // Pre-collect using for loops to avoid borrow conflicts
3053        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3054        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3055            for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {
3056                if let CompiledPostfixOp::Simple { mapping_idx, .. } = postfix_op {
3057                    let mapping = self.index.mappings[*mapping_idx].clone();
3058                    arms.push((pratt_idx, op_idx, mapping));
3059                }
3060            }
3061        }
3062
3063        self.line("match (pratt_id, op_idx) {");
3064        self.indent += 1;
3065
3066        for (pratt_idx, op_idx, mapping) in arms {
3067            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3068            self.indent += 1;
3069            self.line(&format!("let mapping_fn = {};", mapping));
3070            self.line("match mapping_fn(operand, span) {");
3071            self.indent += 1;
3072            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3073            self.line("Err(e) => self.last_error = Some(e),");
3074            self.indent -= 1;
3075            self.line("}");
3076            self.indent -= 1;
3077            self.line("}");
3078        }
3079
3080        self.line("_ => { self.result_stack.push(operand); }");
3081        self.indent -= 1;
3082        self.line("}");
3083    }
3084
3085    fn emit_pratt_postfix_call_arg_handler(&mut self) {
3086        self.line("Work::PrattPostfixCallArg { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column } => {");
3087        self.indent += 1;
3088        self.line("let pratt = &PRATTS[pratt_id as usize];");
3089        self.line("let postfix_op = &pratt.postfix_ops[op_idx as usize];");
3090        self.line("if self.try_consume(postfix_op.close_lit) {");
3091        self.indent += 1;
3092        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3093        self.line("self.work_stack.push(Work::PrattAfterPostfixCall { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column });");
3094        self.indent -= 1;
3095        self.line("} else {");
3096        self.indent += 1;
3097        self.line("self.work_stack.push(Work::PrattPostfixCallSep { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column });");
3098        self.line("if let Some(arg_rule) = postfix_op.arg_rule {");
3099        self.indent += 1;
3100        self.line("self.work_stack.push(Work::Rule { rule_id: arg_rule, result_base: self.result_stack.len() });");
3101        self.indent -= 1;
3102        self.line("} else {");
3103        self.indent += 1;
3104        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: 0, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3105        self.indent -= 1;
3106        self.line("}");
3107        self.indent -= 1;
3108        self.line("}");
3109        self.indent -= 1;
3110        self.line("}");
3111        self.blank();
3112    }
3113
3114    fn emit_pratt_postfix_call_sep_handler(&mut self) {
3115        self.line("Work::PrattPostfixCallSep { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column } => {");
3116        self.indent += 1;
3117        self.line("if self.last_error.is_some() { return Ok(()); }");
3118        self.line("let pratt = &PRATTS[pratt_id as usize];");
3119        self.line("let postfix_op = &pratt.postfix_ops[op_idx as usize];");
3120        self.line("if self.try_consume(postfix_op.sep_lit) {");
3121        self.indent += 1;
3122        // Handle trailing comma: after consuming separator, skip whitespace then check for close delimiter
3123        self.line("let ws_checkpoint = self.pos; let ws_checkpoint_line = self.line; let ws_checkpoint_column = self.column;");
3124        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3125        self.line("if self.try_consume(postfix_op.close_lit) {");
3126        self.indent += 1;
3127        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3128        self.line("self.work_stack.push(Work::PrattAfterPostfixCall { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column });");
3129        self.indent -= 1;
3130        self.line("} else {");
3131        self.indent += 1;
3132        // Restore position so the argument rule can consume whitespace
3133        self.line("self.pos = ws_checkpoint; self.line = ws_checkpoint_line; self.column = ws_checkpoint_column;");
3134        self.line("self.work_stack.push(Work::PrattPostfixCallSep { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column });");
3135        self.line("if let Some(arg_rule) = postfix_op.arg_rule {");
3136        self.indent += 1;
3137        self.line("self.work_stack.push(Work::Rule { rule_id: arg_rule, result_base: self.result_stack.len() });");
3138        self.indent -= 1;
3139        self.line("} else {");
3140        self.indent += 1;
3141        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: 0, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3142        self.indent -= 1;
3143        self.line("}");
3144        self.indent -= 1;
3145        self.line("}");
3146        self.indent -= 1;
3147        self.line("} else if self.try_consume(postfix_op.close_lit) {");
3148        self.indent += 1;
3149        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3150        self.line("self.work_stack.push(Work::PrattAfterPostfixCall { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column });");
3151        self.indent -= 1;
3152        self.line("} else {");
3153        self.indent += 1;
3154        self.line("self.last_error = Some(self.make_error(&format!(\"expected '{}' or '{}'\", postfix_op.sep_lit, postfix_op.close_lit)));");
3155        self.indent -= 1;
3156        self.line("}");
3157        self.indent -= 1;
3158        self.line("}");
3159        self.blank();
3160    }
3161
3162    fn emit_pratt_after_postfix_call_handler(&mut self) {
3163        self.line("Work::PrattAfterPostfixCall { pratt_id, result_base, min_prec, op_idx, args_base, start_pos, start_line, start_column } => {");
3164        self.indent += 1;
3165        self.line("if self.last_error.is_some() { return Ok(()); }");
3166        self.line("let args: Vec<ParseResult> = self.result_stack.drain(args_base..).collect();");
3167        self.line("let callee = self.result_stack.pop().unwrap_or(ParseResult::None);");
3168        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3169        self.emit_postfix_call_mapping_dispatch();
3170        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3171        self.indent -= 1;
3172        self.line("}");
3173        self.blank();
3174    }
3175
3176    fn emit_postfix_call_mapping_dispatch(&mut self) {
3177        // Pre-collect using for loops to avoid borrow conflicts
3178        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3179        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3180            for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {
3181                if let CompiledPostfixOp::Call { mapping_idx, .. } = postfix_op {
3182                    let mapping = self.index.mappings[*mapping_idx].clone();
3183                    arms.push((pratt_idx, op_idx, mapping));
3184                }
3185            }
3186        }
3187
3188        self.line("match (pratt_id, op_idx) {");
3189        self.indent += 1;
3190
3191        for (pratt_idx, op_idx, mapping) in arms {
3192            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3193            self.indent += 1;
3194            self.line(&format!("let mapping_fn = {};", mapping));
3195            self.line("match mapping_fn(callee, args, span) {");
3196            self.indent += 1;
3197            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3198            self.line("Err(e) => self.last_error = Some(e),");
3199            self.indent -= 1;
3200            self.line("}");
3201            self.indent -= 1;
3202            self.line("}");
3203        }
3204
3205        self.line("_ => { self.result_stack.push(callee); }");
3206        self.indent -= 1;
3207        self.line("}");
3208    }
3209
3210    fn emit_pratt_after_postfix_index_handler(&mut self) {
3211        self.line("Work::PrattAfterPostfixIndex { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
3212        self.indent += 1;
3213        self.line("if self.last_error.is_some() { return Ok(()); }");
3214        self.line("let pratt = &PRATTS[pratt_id as usize];");
3215        self.line("let postfix_op = &pratt.postfix_ops[op_idx as usize];");
3216        self.line("if !self.try_consume(postfix_op.close_lit) {");
3217        self.indent += 1;
3218        self.line("self.last_error = Some(self.make_error(&format!(\"expected '{}'\", postfix_op.close_lit)));");
3219        self.line("return Ok(());");
3220        self.indent -= 1;
3221        self.line("}");
3222        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3223        self.line("let index_expr = self.result_stack.pop().unwrap_or(ParseResult::None);");
3224        self.line("let obj = self.result_stack.pop().unwrap_or(ParseResult::None);");
3225        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3226        self.emit_postfix_index_mapping_dispatch();
3227        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3228        self.indent -= 1;
3229        self.line("}");
3230        self.blank();
3231    }
3232
3233    fn emit_postfix_index_mapping_dispatch(&mut self) {
3234        // Pre-collect using for loops to avoid borrow conflicts
3235        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3236        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3237            for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {
3238                if let CompiledPostfixOp::Index { mapping_idx, .. } = postfix_op {
3239                    let mapping = self.index.mappings[*mapping_idx].clone();
3240                    arms.push((pratt_idx, op_idx, mapping));
3241                }
3242            }
3243        }
3244
3245        self.line("match (pratt_id, op_idx) {");
3246        self.indent += 1;
3247
3248        for (pratt_idx, op_idx, mapping) in arms {
3249            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3250            self.indent += 1;
3251            self.line(&format!("let mapping_fn = {};", mapping));
3252            self.line("match mapping_fn(obj, index_expr, span) {");
3253            self.indent += 1;
3254            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3255            self.line("Err(e) => self.last_error = Some(e),");
3256            self.indent -= 1;
3257            self.line("}");
3258            self.indent -= 1;
3259            self.line("}");
3260        }
3261
3262        self.line("_ => { self.result_stack.push(obj); }");
3263        self.indent -= 1;
3264        self.line("}");
3265    }
3266
3267    fn emit_pratt_after_postfix_member_handler(&mut self) {
3268        self.line("Work::PrattAfterPostfixMember { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
3269        self.indent += 1;
3270        self.line("let ident_start = self.pos;");
3271        self.line("let is_ident_start = self.current_char().map_or(false, |c| c.is_ascii_alphabetic() || c == '_' || c == '$' || c == '#');");
3272        self.line("let is_unicode_escape = self.input.get(self.pos..).map_or(false, |s| s.starts_with(\"\\\\u\"));");
3273        self.line("if is_ident_start || is_unicode_escape {");
3274        self.indent += 1;
3275        self.line("// Parse identifier");
3276        self.line("if is_unicode_escape {");
3277        self.indent += 1;
3278        self.line("self.advance(); self.advance(); // Skip \\u");
3279        self.line("if self.current_char() == Some('{') {");
3280        self.indent += 1;
3281        self.line("// \\u{...} format");
3282        self.line("self.advance();");
3283        self.line("while self.current_char().map_or(false, |c| c.is_ascii_hexdigit()) { self.advance(); }");
3284        self.line("if self.current_char() == Some('}') { self.advance(); }");
3285        self.indent -= 1;
3286        self.line("} else {");
3287        self.indent += 1;
3288        self.line("// \\uXXXX format");
3289        self.line("for _ in 0..4 { if self.current_char().map_or(false, |c| c.is_ascii_hexdigit()) { self.advance(); } }");
3290        self.indent -= 1;
3291        self.line("}");
3292        self.indent -= 1;
3293        self.line("}");
3294        self.line("else { self.advance(); }");
3295        self.line("loop {");
3296        self.indent += 1;
3297        self.line("if self.current_char().map_or(false, |c| c.is_ascii_alphanumeric() || c == '_' || c == '$') { self.advance(); }");
3298        self.line(
3299            "else if self.input.get(self.pos..).map_or(false, |s| s.starts_with(\"\\\\u\")) {",
3300        );
3301        self.indent += 1;
3302        self.line("// Unicode escape in identifier continuation");
3303        self.line("self.advance(); self.advance(); // Skip \\u");
3304        self.line("if self.current_char() == Some('{') {");
3305        self.indent += 1;
3306        self.line("// \\u{...} format");
3307        self.line("self.advance();");
3308        self.line("while self.current_char().map_or(false, |c| c.is_ascii_hexdigit()) { self.advance(); }");
3309        self.line("if self.current_char() == Some('}') { self.advance(); }");
3310        self.indent -= 1;
3311        self.line("} else {");
3312        self.indent += 1;
3313        self.line("// \\uXXXX format");
3314        self.line("for _ in 0..4 { if self.current_char().map_or(false, |c| c.is_ascii_hexdigit()) { self.advance(); } }");
3315        self.indent -= 1;
3316        self.line("}");
3317        self.indent -= 1;
3318        self.line("} else { break; }");
3319        self.indent -= 1;
3320        self.line("}");
3321        self.line("let prop_name = self.text_result(ident_start, self.pos);");
3322        self.line("while self.current_char().map_or(false, |c| c.is_ascii_whitespace()) { self.advance(); }");
3323        self.line("let obj = self.result_stack.pop().unwrap_or(ParseResult::None);");
3324        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3325        self.emit_postfix_member_mapping_dispatch();
3326        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3327        self.indent -= 1;
3328        self.line("} else {");
3329        self.indent += 1;
3330        self.line("self.last_error = Some(self.make_error(\"expected identifier\"));");
3331        self.indent -= 1;
3332        self.line("}");
3333        self.indent -= 1;
3334        self.line("}");
3335        self.blank();
3336    }
3337
3338    fn emit_postfix_member_mapping_dispatch(&mut self) {
3339        // Pre-collect using for loops to avoid borrow conflicts
3340        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3341        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3342            for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {
3343                if let CompiledPostfixOp::Member { mapping_idx, .. } = postfix_op {
3344                    let mapping = self.index.mappings[*mapping_idx].clone();
3345                    arms.push((pratt_idx, op_idx, mapping));
3346                }
3347            }
3348        }
3349
3350        self.line("match (pratt_id, op_idx) {");
3351        self.indent += 1;
3352
3353        for (pratt_idx, op_idx, mapping) in arms {
3354            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3355            self.indent += 1;
3356            self.line(&format!("let mapping_fn = {};", mapping));
3357            self.line("match mapping_fn(obj, prop_name, span) {");
3358            self.indent += 1;
3359            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3360            self.line("Err(e) => self.last_error = Some(e),");
3361            self.indent -= 1;
3362            self.line("}");
3363            self.indent -= 1;
3364            self.line("}");
3365        }
3366
3367        self.line("_ => { self.result_stack.push(obj); }");
3368        self.indent -= 1;
3369        self.line("}");
3370    }
3371
3372    fn emit_pratt_after_postfix_rule_handler(&mut self) {
3373        self.line("Work::PrattAfterPostfixRule { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
3374        self.indent += 1;
3375        self.line("if self.last_error.is_some() { return Ok(()); }");
3376        self.line("let rule_result = self.result_stack.pop().unwrap_or(ParseResult::None);");
3377        self.line("let obj = self.result_stack.pop().unwrap_or(ParseResult::None);");
3378        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3379        self.emit_postfix_rule_mapping_dispatch();
3380        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3381        self.indent -= 1;
3382        self.line("}");
3383        self.blank();
3384    }
3385
3386    fn emit_postfix_rule_mapping_dispatch(&mut self) {
3387        // Pre-collect using for loops to avoid borrow conflicts
3388        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3389        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3390            for (op_idx, postfix_op) in pratt.postfix_ops.iter().enumerate() {
3391                if let CompiledPostfixOp::Rule { mapping_idx, .. } = postfix_op {
3392                    let mapping = self.index.mappings[*mapping_idx].clone();
3393                    arms.push((pratt_idx, op_idx, mapping));
3394                }
3395            }
3396        }
3397
3398        self.line("match (pratt_id, op_idx) {");
3399        self.indent += 1;
3400
3401        for (pratt_idx, op_idx, mapping) in arms {
3402            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3403            self.indent += 1;
3404            self.line(&format!("let mapping_fn = {};", mapping));
3405            self.line("match mapping_fn(obj, rule_result, span) {");
3406            self.indent += 1;
3407            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3408            self.line("Err(e) => self.last_error = Some(e),");
3409            self.indent -= 1;
3410            self.line("}");
3411            self.indent -= 1;
3412            self.line("}");
3413        }
3414
3415        self.line("_ => { self.result_stack.push(obj); }");
3416        self.indent -= 1;
3417        self.line("}");
3418    }
3419
3420    fn emit_pratt_after_operand_handler(&mut self) {
3421        self.line("Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column } => {");
3422        self.indent += 1;
3423        self.line("if self.last_error.is_some() { return Ok(()); }");
3424        self.line("let pratt = &PRATTS[pratt_id as usize];");
3425        self.line("let infix_checkpoint = self.pos;");
3426        self.blank();
3427
3428        // Try simple infix operators first
3429        self.line("// Try simple infix operators (no leading rule)");
3430        self.line("for (op_idx, infix_op) in pratt.infix_ops.iter().enumerate() {");
3431        self.indent += 1;
3432        self.line("if self.pos != infix_checkpoint { break; } // Already matched one");
3433        self.line("if infix_op.precedence < min_prec { continue; }");
3434        self.line("if infix_op.leading_rule.is_some() { continue; }");
3435        self.line("if infix_op.literal.is_empty() { continue; }");
3436        self.blank();
3437        self.line("let mut can_match = self.input.get(self.pos..).unwrap_or(\"\").starts_with(infix_op.literal);");
3438        self.line("if can_match {");
3439        self.indent += 1;
3440        self.line("for nfb in infix_op.not_followed_by {");
3441        self.indent += 1;
3442        self.line("let combined = format!(\"{}{}\", infix_op.literal, nfb);");
3443        self.line("if self.input.get(self.pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
3444        self.indent -= 1;
3445        self.line("}");
3446        self.indent -= 1;
3447        self.line("}");
3448        self.blank();
3449        self.line("if can_match {");
3450        self.indent += 1;
3451        self.line("self.pos += infix_op.literal.len();");
3452        self.line("self.column += infix_op.literal.len() as u32;");
3453        self.line("if infix_op.is_keyword {");
3454        self.indent += 1;
3455        self.line("if !self.current_char().map_or(true, |c| !(c.is_ascii_alphanumeric() || c == '_' || c == '$')) {");
3456        self.indent += 1;
3457        self.line("self.pos = infix_checkpoint;");
3458        self.line("continue;");
3459        self.indent -= 1;
3460        self.line("}");
3461        self.indent -= 1;
3462        self.line("}");
3463        self.line("let next_prec = if infix_op.is_left_assoc { infix_op.precedence + 1 } else { infix_op.precedence };");
3464        self.line("self.work_stack.push(Work::PrattAfterInfix { pratt_id, result_base, min_prec, op_idx: op_idx as u8, start_pos, start_line, start_column });");
3465        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: next_prec, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3466        self.indent -= 1;
3467        self.line("}");
3468        self.indent -= 1;
3469        self.line("}");
3470        self.blank();
3471
3472        // Try ternary operator
3473        self.line("// Try ternary operator");
3474        self.line("if self.pos == infix_checkpoint {");
3475        self.indent += 1;
3476        self.line("if let Some(ref ternary) = pratt.ternary {");
3477        self.indent += 1;
3478        self.line("if ternary.precedence >= min_prec {");
3479        self.indent += 1;
3480        self.line("// Check for ternary but not ?. or ??");
3481        self.line("let rest = self.input.get(self.pos..).unwrap_or(\"\");");
3482        self.line("if rest.starts_with(ternary.first_lit) && !rest.starts_with(\"?.\") && !rest.starts_with(\"??\") {");
3483        self.indent += 1;
3484        self.line("self.pos += ternary.first_lit.len();");
3485        self.line("self.column += ternary.first_lit.len() as u32;");
3486        self.line("self.work_stack.push(Work::PrattAfterTernaryFirst { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3487        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: 0, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3488        self.indent -= 1;
3489        self.line("}");
3490        self.indent -= 1;
3491        self.line("}");
3492        self.indent -= 1;
3493        self.line("}");
3494        self.indent -= 1;
3495        self.line("}");
3496        self.blank();
3497
3498        // Try infix with leading rule
3499        self.line("// Try infix operators with leading rule");
3500        self.line("if self.pos == infix_checkpoint && pratt.has_infix_with_leading {");
3501        self.indent += 1;
3502        self.line("// Find max precedence of infix ops with leading rule");
3503        self.line("let max_prec = pratt.infix_ops.iter().filter(|op| op.leading_rule.is_some()).map(|op| op.precedence).max().unwrap_or(0);");
3504        self.line("if max_prec >= min_prec {");
3505        self.indent += 1;
3506        self.line("if let Some((op_idx, infix_op)) = pratt.infix_ops.iter().enumerate().find(|(_, op)| op.leading_rule.is_some()) {");
3507        self.indent += 1;
3508        self.line("let next_prec = if infix_op.is_left_assoc { infix_op.precedence + 1 } else { infix_op.precedence };");
3509        self.line("self.work_stack.push(Work::PrattAfterInfixLeadingRule { pratt_id, result_base, min_prec, op_idx: op_idx as u8, next_prec, checkpoint: infix_checkpoint, checkpoint_line: self.line, checkpoint_column: self.column, start_pos, start_line, start_column });");
3510        self.line("if let Some(rule_id) = infix_op.leading_rule {");
3511        self.indent += 1;
3512        self.line(
3513            "self.work_stack.push(Work::Rule { rule_id, result_base: self.result_stack.len() });",
3514        );
3515        self.indent -= 1;
3516        self.line("}");
3517        self.indent -= 1;
3518        self.line("}");
3519        self.indent -= 1;
3520        self.line("}");
3521        self.indent -= 1;
3522        self.line("}");
3523        self.indent -= 1;
3524        self.line("}");
3525        self.blank();
3526    }
3527
3528    fn emit_pratt_after_infix_handler(&mut self) {
3529        self.line("Work::PrattAfterInfix { pratt_id, result_base, min_prec, op_idx, start_pos, start_line, start_column } => {");
3530        self.indent += 1;
3531        self.line("if self.last_error.is_some() { return Ok(()); }");
3532        self.line("let right = self.result_stack.pop().unwrap_or(ParseResult::None);");
3533        self.line("let left = self.result_stack.pop().unwrap_or(ParseResult::None);");
3534        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3535        self.emit_infix_mapping_dispatch();
3536        self.line("// Continue with postfix/infix loop");
3537        self.line("let pratt = &PRATTS[pratt_id as usize];");
3538        self.line("if !pratt.postfix_ops.is_empty() {");
3539        self.indent += 1;
3540        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3541        self.indent -= 1;
3542        self.line("} else {");
3543        self.indent += 1;
3544        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3545        self.indent -= 1;
3546        self.line("}");
3547        self.indent -= 1;
3548        self.line("}");
3549        self.blank();
3550    }
3551
3552    fn emit_infix_mapping_dispatch(&mut self) {
3553        // Pre-collect using for loops to avoid borrow conflicts
3554        let mut arms: Vec<(usize, usize, String)> = Vec::new();
3555        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3556            for (op_idx, infix_op) in pratt.infix_ops.iter().enumerate() {
3557                let mapping = self.index.mappings[infix_op.mapping_idx].clone();
3558                arms.push((pratt_idx, op_idx, mapping));
3559            }
3560        }
3561
3562        self.line("match (pratt_id, op_idx) {");
3563        self.indent += 1;
3564
3565        for (pratt_idx, op_idx, mapping) in arms {
3566            self.line(&format!("({}, {}) => {{", pratt_idx, op_idx));
3567            self.indent += 1;
3568            self.line(&format!("let mapping_fn = {};", mapping));
3569            self.line("match mapping_fn(left, right, span) {");
3570            self.indent += 1;
3571            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3572            self.line("Err(e) => self.last_error = Some(e),");
3573            self.indent -= 1;
3574            self.line("}");
3575            self.indent -= 1;
3576            self.line("}");
3577        }
3578
3579        self.line("_ => { self.result_stack.push(left); }");
3580        self.indent -= 1;
3581        self.line("}");
3582    }
3583
3584    fn emit_pratt_after_infix_leading_rule_handler(&mut self) {
3585        self.line("Work::PrattAfterInfixLeadingRule { pratt_id, result_base, min_prec, op_idx: _, next_prec: _, checkpoint, checkpoint_line, checkpoint_column, start_pos, start_line, start_column } => {");
3586        self.indent += 1;
3587        self.line("let _ = self.result_stack.pop(); // Discard leading rule result");
3588        self.line("self.last_error = None;");
3589        self.line("let pratt = &PRATTS[pratt_id as usize];");
3590        self.line("let after_ws_pos = self.pos;");
3591        self.blank();
3592        self.line("// Try all infix operators with leading rules");
3593        self.line("for (actual_op_idx, infix_op) in pratt.infix_ops.iter().enumerate() {");
3594        self.indent += 1;
3595        self.line("if infix_op.leading_rule.is_none() { continue; }");
3596        self.line("if infix_op.precedence < min_prec { continue; }");
3597        self.line("if infix_op.literal.is_empty() { continue; }");
3598        self.blank();
3599        self.line("let mut can_match = self.input.get(after_ws_pos..).unwrap_or(\"\").starts_with(infix_op.literal);");
3600        self.line("if can_match {");
3601        self.indent += 1;
3602        self.line("for nfb in infix_op.not_followed_by {");
3603        self.indent += 1;
3604        self.line("let combined = format!(\"{}{}\", infix_op.literal, nfb);");
3605        self.line("if self.input.get(after_ws_pos..).unwrap_or(\"\").starts_with(&combined) { can_match = false; break; }");
3606        self.indent -= 1;
3607        self.line("}");
3608        self.indent -= 1;
3609        self.line("}");
3610        self.blank();
3611        self.line("if can_match {");
3612        self.indent += 1;
3613        self.line("self.pos = after_ws_pos + infix_op.literal.len();");
3614        self.line("self.column += infix_op.literal.len() as u32;");
3615        self.line("if infix_op.is_keyword {");
3616        self.indent += 1;
3617        self.line("if !self.current_char().map_or(true, |c| !(c.is_ascii_alphanumeric() || c == '_' || c == '$')) {");
3618        self.indent += 1;
3619        self.line("continue; // Not a valid keyword match, try next operator");
3620        self.indent -= 1;
3621        self.line("}");
3622        self.indent -= 1;
3623        self.line("}");
3624        self.line("let next_prec = if infix_op.is_left_assoc { infix_op.precedence + 1 } else { infix_op.precedence };");
3625        self.line("self.work_stack.push(Work::PrattAfterInfix { pratt_id, result_base, min_prec, op_idx: actual_op_idx as u8, start_pos, start_line, start_column });");
3626        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: next_prec, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3627        self.line("return Ok(());");
3628        self.indent -= 1;
3629        self.line("}");
3630        self.indent -= 1;
3631        self.line("}");
3632        self.blank();
3633        self.line("// No operator matched - restore checkpoint");
3634        self.line("self.pos = checkpoint;");
3635        self.line("self.line = checkpoint_line;");
3636        self.line("self.column = checkpoint_column;");
3637        self.indent -= 1;
3638        self.line("}");
3639        self.blank();
3640    }
3641
3642    fn emit_pratt_after_ternary_first_handler(&mut self) {
3643        self.line("Work::PrattAfterTernaryFirst { pratt_id, result_base, min_prec, start_pos, start_line, start_column } => {");
3644        self.indent += 1;
3645        self.line("if self.last_error.is_some() { return Ok(()); }");
3646        self.line("let pratt = &PRATTS[pratt_id as usize];");
3647        self.line(
3648            "while self.current_char().map_or(false, |c| c.is_whitespace()) { self.advance(); }",
3649        );
3650        self.line("if let Some(ref ternary) = pratt.ternary {");
3651        self.indent += 1;
3652        self.line("if self.try_consume(ternary.second_lit) {");
3653        self.indent += 1;
3654        self.line("self.work_stack.push(Work::PrattAfterTernarySecond { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3655        self.line("self.work_stack.push(Work::PrattParseOperand { pratt_id, result_base: self.result_stack.len(), min_prec: ternary.precedence, start_pos: self.pos, start_line: self.line, start_column: self.column });");
3656        self.indent -= 1;
3657        self.line("} else {");
3658        self.indent += 1;
3659        self.line("self.last_error = Some(self.make_error(&format!(\"Expected '{}' in ternary expression\", ternary.second_lit)));");
3660        self.indent -= 1;
3661        self.line("}");
3662        self.indent -= 1;
3663        self.line("}");
3664        self.indent -= 1;
3665        self.line("}");
3666        self.blank();
3667    }
3668
3669    fn emit_pratt_after_ternary_second_handler(&mut self) {
3670        self.line("Work::PrattAfterTernarySecond { pratt_id, result_base, min_prec, start_pos, start_line, start_column } => {");
3671        self.indent += 1;
3672        self.line("if self.last_error.is_some() { return Ok(()); }");
3673        self.line("let alternate = self.result_stack.pop().unwrap_or(ParseResult::None);");
3674        self.line("let consequent = self.result_stack.pop().unwrap_or(ParseResult::None);");
3675        self.line("let test = self.result_stack.pop().unwrap_or(ParseResult::None);");
3676        self.line("let span = Span { start: start_pos, end: self.pos, line: start_line, column: start_column };");
3677        self.emit_ternary_mapping_dispatch();
3678        self.line("// Continue with postfix/infix loop");
3679        self.line("let pratt = &PRATTS[pratt_id as usize];");
3680        self.line("if !pratt.postfix_ops.is_empty() {");
3681        self.indent += 1;
3682        self.line("self.work_stack.push(Work::PrattCheckPostfix { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3683        self.indent -= 1;
3684        self.line("} else {");
3685        self.indent += 1;
3686        self.line("self.work_stack.push(Work::PrattAfterOperand { pratt_id, result_base, min_prec, start_pos, start_line, start_column });");
3687        self.indent -= 1;
3688        self.line("}");
3689        self.indent -= 1;
3690        self.line("}");
3691        self.blank();
3692    }
3693
3694    fn emit_ternary_mapping_dispatch(&mut self) {
3695        // Pre-collect using for loops to avoid borrow conflicts
3696        let mut arms: Vec<(usize, String)> = Vec::new();
3697        for (pratt_idx, pratt) in self.index.pratts.iter().enumerate() {
3698            if let Some(ternary) = &pratt.ternary {
3699                let mapping = self.index.mappings[ternary.mapping_idx].clone();
3700                arms.push((pratt_idx, mapping));
3701            }
3702        }
3703
3704        self.line("match pratt_id {");
3705        self.indent += 1;
3706
3707        for (pratt_idx, mapping) in arms {
3708            self.line(&format!("{} => {{", pratt_idx));
3709            self.indent += 1;
3710            self.line(&format!("let mapping_fn = {};", mapping));
3711            self.line("match mapping_fn(test, consequent, alternate, span) {");
3712            self.indent += 1;
3713            self.line("Ok(mapped) => self.result_stack.push(mapped),");
3714            self.line("Err(e) => self.last_error = Some(e),");
3715            self.indent -= 1;
3716            self.line("}");
3717            self.indent -= 1;
3718            self.line("}");
3719        }
3720
3721        self.line("_ => { self.result_stack.push(test); }");
3722        self.indent -= 1;
3723        self.line("}");
3724    }
3725
3726    /// Emit the indexed parser struct and methods
3727    fn emit_indexed_parser(&mut self) {
3728        let string_type = self
3729            .grammar
3730            .ast_config
3731            .string_type
3732            .as_deref()
3733            .unwrap_or("String");
3734
3735        let has_string_dict = self.grammar.ast_config.string_dict_type.is_some();
3736        let string_dict_type = self
3737            .grammar
3738            .ast_config
3739            .string_dict_type
3740            .as_deref()
3741            .unwrap_or("StringDict");
3742
3743        self.line("/// Scannerless parser (indexed dispatch)");
3744        self.line("pub struct Parser<'a> {");
3745        self.indent += 1;
3746        self.line("input: &'a str,");
3747        self.line("pos: usize,");
3748        self.line("line: u32,");
3749        self.line("column: u32,");
3750        self.line("work_stack: Vec<Work>,");
3751        self.line("result_stack: Vec<ParseResult>,");
3752        self.line("last_error: Option<ParseError>,");
3753        self.line(
3754            "memo: hashbrown::HashMap<(usize, usize), Option<(ParseResult, usize, u32, u32)>>,",
3755        );
3756        if has_string_dict {
3757            self.line(&format!("string_dict: &'a mut {},", string_dict_type));
3758        }
3759        self.indent -= 1;
3760        self.line("}");
3761        self.blank();
3762
3763        self.line("impl<'a> Parser<'a> {");
3764        self.indent += 1;
3765
3766        // Constructor
3767        if has_string_dict {
3768            self.line(&format!(
3769                "pub fn new(input: &'a str, string_dict: &'a mut {}) -> Self {{",
3770                string_dict_type
3771            ));
3772        } else {
3773            self.line("pub fn new(input: &'a str) -> Self {");
3774        }
3775        self.indent += 1;
3776        self.line("Self {");
3777        self.indent += 1;
3778        self.line("input,");
3779        self.line("pos: 0,");
3780        self.line("line: 1,");
3781        self.line("column: 1,");
3782        self.line("work_stack: Vec::new(),");
3783        self.line("result_stack: Vec::new(),");
3784        self.line("last_error: None,");
3785        self.line("memo: hashbrown::HashMap::new(),");
3786        if has_string_dict {
3787            self.line("string_dict,");
3788        }
3789        self.indent -= 1;
3790        self.line("}");
3791        self.indent -= 1;
3792        self.line("}");
3793        self.blank();
3794
3795        // Parse entry point for first rule
3796        if !self.grammar.rules.is_empty() {
3797            self.line("/// Parse the input");
3798            self.line("pub fn parse(&mut self) -> Result<ParseResult, ParseError> {");
3799            self.indent += 1;
3800            self.line("let result_base = self.result_stack.len();");
3801            // Dispatch to first rule using indexed approach
3802            self.line("self.work_stack.push(Work::Rule { rule_id: 0, result_base });");
3803            self.line("self.run()?;");
3804            self.line("self.result_stack.pop().ok_or_else(|| ParseError {");
3805            self.indent += 1;
3806            self.line("message: \"No result\".to_string(),");
3807            self.line(
3808                "span: Span { start: 0, end: self.pos, line: self.line, column: self.column },",
3809            );
3810            self.indent -= 1;
3811            self.line("})");
3812            self.indent -= 1;
3813            self.line("}");
3814            self.blank();
3815        }
3816
3817        // Helper methods
3818        self.emit_helper_methods(string_type);
3819
3820        // Apply mapping method (for AST transformations)
3821        self.emit_apply_mapping_method();
3822
3823        // Trampoline loop
3824        self.line("fn run(&mut self) -> Result<(), ParseError> {");
3825        self.indent += 1;
3826        self.line("while let Some(work) = self.work_stack.pop() {");
3827        self.indent += 1;
3828        self.line("self.execute(work)?;");
3829        self.indent -= 1;
3830        self.line("}");
3831        self.line("if let Some(err) = self.last_error.take() {");
3832        self.indent += 1;
3833        self.line("return Err(err);");
3834        self.indent -= 1;
3835        self.line("}");
3836        self.line("Ok(())");
3837        self.indent -= 1;
3838        self.line("}");
3839        self.blank();
3840
3841        // Dispatch helper
3842        self.emit_dispatch_combref();
3843
3844        // Execute method
3845        self.emit_indexed_execute();
3846
3847        self.indent -= 1;
3848        self.line("}");
3849    }
3850}
3851
3852/// Convert a CombRef to its generated code representation
3853fn combref_to_code(cref: &CombRef) -> String {
3854    match cref {
3855        CombRef::Rule(id) => format!("CombRef::Rule({})", id),
3856        CombRef::Seq(id) => format!("CombRef::Seq({})", id),
3857        CombRef::Choice(id) => format!("CombRef::Choice({})", id),
3858        CombRef::ZeroOrMore(id) => format!("CombRef::ZeroOrMore({})", id),
3859        CombRef::OneOrMore(id) => format!("CombRef::OneOrMore({})", id),
3860        CombRef::Optional(id) => format!("CombRef::Optional({})", id),
3861        CombRef::Literal(id) => format!("CombRef::Literal({})", id),
3862        CombRef::CharClass(class) => format!("CombRef::CharClass({})", *class as u8),
3863        CombRef::CharRange(from, to) => format!("CombRef::CharRange({:?}, {:?})", from, to),
3864        CombRef::Char(c) => format!("CombRef::Char({:?})", c),
3865        CombRef::AnyChar => "CombRef::AnyChar".to_string(),
3866        CombRef::Capture(id) => format!("CombRef::Capture({})", id),
3867        CombRef::NotFollowedBy(id) => format!("CombRef::NotFollowedBy({})", id),
3868        CombRef::FollowedBy(id) => format!("CombRef::FollowedBy({})", id),
3869        CombRef::Skip(id) => format!("CombRef::Skip({})", id),
3870        CombRef::SeparatedBy(id) => format!("CombRef::SeparatedBy({})", id),
3871        CombRef::Pratt(id) => format!("CombRef::Pratt({})", id),
3872        CombRef::Mapped(id) => format!("CombRef::Mapped({})", id),
3873        CombRef::Memoize(id) => format!("CombRef::Memoize({})", id),
3874    }
3875}
3876
3877#[cfg(test)]
3878mod tests {
3879    use crate::Grammar;
3880
3881    #[test]
3882    fn test_simple_grammar_generates() {
3883        let grammar = Grammar::new().rule("digit", |r| r.digit()).build();
3884
3885        let code = grammar.generate();
3886        assert!(code.contains("pub struct Parser"));
3887        assert!(code.contains("enum Work"));
3888    }
3889
3890    #[test]
3891    fn test_indexed_grammar_generates() {
3892        let grammar = Grammar::new()
3893            .rule("number", |r| r.capture(r.one_or_more(r.digit())))
3894            .rule("ws", |r| r.zero_or_more(r.lit(" ")))
3895            .build();
3896
3897        let code = grammar.generate();
3898
3899        // Should have the fixed Work enum with indexed variants
3900        assert!(code.contains("pub struct Parser"));
3901        assert!(code.contains("enum Work"));
3902        assert!(code.contains("enum CombRef"));
3903
3904        // Should have static dispatch tables
3905        assert!(code.contains("static SEQUENCES:"));
3906        assert!(code.contains("static CAPTURES:"));
3907        assert!(code.contains("static LITERALS:"));
3908        assert!(code.contains("static RULES:"));
3909
3910        // Should have indexed Work variants (not path-based ones)
3911        assert!(code.contains("SeqStart { seq_id:"));
3912        assert!(code.contains("CaptureStart { cap_id:"));
3913
3914        // Should NOT have recursive path-based variants like NumberStart or WsStart
3915        // (The indexed approach doesn't generate rule-name-prefixed variants)
3916        assert!(!code.contains("NumberStart {"));
3917        assert!(!code.contains("WsStart {"));
3918    }
3919
3920    #[test]
3921    fn test_indexed_variant_count() {
3922        // Verify the indexed approach produces a bounded number of Work variants
3923        let grammar = Grammar::new()
3924            .rule("expr", |r| {
3925                r.choice((
3926                    r.sequence((r.parse("number"), r.lit("+"), r.parse("expr"))),
3927                    r.sequence((r.parse("number"), r.lit("-"), r.parse("expr"))),
3928                    r.parse("number"),
3929                ))
3930            })
3931            .rule("number", |r| r.capture(r.one_or_more(r.digit())))
3932            .build();
3933
3934        let code = grammar.generate();
3935
3936        // Count Work variants by extracting the enum section
3937        fn count_work_variants(code: &str) -> usize {
3938            let start = code.find("enum Work {").unwrap_or(0);
3939            let end_search = &code[start..];
3940            let mut count = 0;
3941            let mut in_enum = false;
3942            for line in end_search.lines() {
3943                if line.contains("enum Work {") {
3944                    in_enum = true;
3945                    continue;
3946                }
3947                if in_enum && line.trim() == "}" {
3948                    break;
3949                }
3950                if in_enum && line.contains(" { ") && line.trim().ends_with("},") {
3951                    count += 1;
3952                }
3953            }
3954            count
3955        }
3956
3957        let variants = count_work_variants(&code);
3958
3959        // The indexed approach should have a fixed ~50-55 variants regardless of grammar size
3960        assert!(
3961            variants <= 60,
3962            "Should have ~50 fixed variants, got {}",
3963            variants
3964        );
3965    }
3966}