1use 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
17pub struct CodeGenerator<'a> {
19 grammar: &'a CompiledGrammar,
20 output: String,
21 indent: usize,
22 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 pub fn generate(mut self) -> String {
42 self.index_combinators();
44
45 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 fn index_combinators(&mut self) {
61 for (i, rule) in self.grammar.rules.iter().enumerate() {
63 self.index.rule_map.insert(rule.name.clone(), i as u16);
64 }
65
66 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 fn index_combinator(&mut self, comb: &Combinator) -> CombRef {
78 match comb {
79 Combinator::Rule(name) => {
80 if let Some(&rule_id) = self.index.rule_map.get(name) {
82 CombRef::Rule(rule_id)
83 } else {
84 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 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 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 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 let postfix_ops: Vec<CompiledPostfixOp> = pratt_def
246 .postfix_ops
247 .iter()
248 .map(|op| self.index_postfix_op(op))
249 .collect();
250
251 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 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 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 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 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 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 fn extract_literal(&self, comb: &Combinator) -> String {
372 match comb {
373 Combinator::Literal(lit) => lit.clone(),
374 Combinator::Sequence(items) => {
375 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 fn intern_mapping(&mut self, mapping: &str) -> usize {
389 for (i, existing) in self.index.mappings.iter().enumerate() {
391 if existing == mapping {
392 return i;
393 }
394 }
395 let idx = self.index.mappings.len();
397 self.index.mappings.push(mapping.to_string());
398 idx
399 }
400
401 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 self.line("/// Dispatch to a rule by ID");
959 self.line("Rule { rule_id: u16, result_base: usize },");
960 self.blank();
961
962 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 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 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 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 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 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 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 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 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 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 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 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 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 fn emit_static_tables(&mut self) {
1109 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 self.emit_pratt_static_tables();
1406 }
1407
1408 fn emit_pratt_static_tables(&mut self) {
1410 if self.index.pratts.is_empty() {
1411 return;
1412 }
1413
1414 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 let pratt_defs: Vec<String> = self.build_pratt_defs();
1500
1501 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 self.emit_pratt_operator_arrays();
1514 }
1515
1516 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 #[allow(clippy::type_complexity)]
1544 fn emit_pratt_operator_arrays(&mut self) {
1545 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 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 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 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 for (pratt_idx, prefix_lines, infix_lines, postfix_lines) in pratt_arrays {
1719 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 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 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 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 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 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 self.emit_indexed_seq_handlers();
1816
1817 self.emit_indexed_choice_handlers();
1819
1820 self.emit_indexed_zero_or_more_handlers();
1822
1823 self.emit_indexed_one_or_more_handlers();
1825
1826 self.emit_indexed_optional_handlers();
1828
1829 self.emit_indexed_capture_handlers();
1831
1832 self.emit_indexed_lookahead_handlers();
1834
1835 self.emit_indexed_skip_handlers();
1837
1838 self.emit_indexed_separated_by_handlers();
1840
1841 self.emit_indexed_mapped_handlers();
1843
1844 self.emit_indexed_memoize_handlers();
1846
1847 self.emit_indexed_terminal_handlers();
1849
1850 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 self.emit_pratt_parse_operand_handler();
2621
2622 self.emit_pratt_after_prefix_handler();
2624
2625 self.emit_pratt_after_prefix_leading_rule_handler();
2627
2628 self.emit_pratt_check_postfix_handler();
2630
2631 self.emit_pratt_after_postfix_simple_handler();
2633
2634 self.emit_pratt_postfix_call_arg_handler();
2636
2637 self.emit_pratt_postfix_call_sep_handler();
2639
2640 self.emit_pratt_after_postfix_call_handler();
2642
2643 self.emit_pratt_after_postfix_index_handler();
2645
2646 self.emit_pratt_after_postfix_member_handler();
2648
2649 self.emit_pratt_after_postfix_rule_handler();
2651
2652 self.emit_pratt_after_operand_handler();
2654
2655 self.emit_pratt_after_infix_handler();
2657
2658 self.emit_pratt_after_infix_leading_rule_handler();
2660
2661 self.emit_pratt_after_ternary_first_handler();
2663
2664 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 self.emit_helper_methods(string_type);
3819
3820 self.emit_apply_mapping_method();
3822
3823 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 self.emit_dispatch_combref();
3843
3844 self.emit_indexed_execute();
3846
3847 self.indent -= 1;
3848 self.line("}");
3849 }
3850}
3851
3852fn 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 assert!(code.contains("pub struct Parser"));
3901 assert!(code.contains("enum Work"));
3902 assert!(code.contains("enum CombRef"));
3903
3904 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 assert!(code.contains("SeqStart { seq_id:"));
3912 assert!(code.contains("CaptureStart { cap_id:"));
3913
3914 assert!(!code.contains("NumberStart {"));
3917 assert!(!code.contains("WsStart {"));
3918 }
3919
3920 #[test]
3921 fn test_indexed_variant_count() {
3922 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 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 assert!(
3961 variants <= 60,
3962 "Should have ~50 fixed variants, got {}",
3963 variants
3964 );
3965 }
3966}