1use react_compiler_diagnostics::CompilerError;
2use react_compiler_hir::environment::Environment;
3use react_compiler_hir::print::{self, PrintFormatter};
4use react_compiler_hir::{
5 BasicBlock, BlockId, HirFunction, Instruction, ParamPattern, Place, Terminal,
6};
7
8struct DebugPrinter<'a> {
13 fmt: PrintFormatter<'a>,
14}
15
16impl<'a> DebugPrinter<'a> {
17 fn new(env: &'a Environment) -> Self {
18 Self {
19 fmt: PrintFormatter::new(env),
20 }
21 }
22
23 fn format_function(&mut self, func: &HirFunction) {
28 self.fmt.indent();
29 self.fmt.line(&format!(
30 "id: {}",
31 match &func.id {
32 Some(id) => format!("\"{}\"", id),
33 None => "null".to_string(),
34 }
35 ));
36 self.fmt.line(&format!(
37 "name_hint: {}",
38 match &func.name_hint {
39 Some(h) => format!("\"{}\"", h),
40 None => "null".to_string(),
41 }
42 ));
43 self.fmt.line(&format!("fn_type: {:?}", func.fn_type));
44 self.fmt.line(&format!("generator: {}", func.generator));
45 self.fmt.line(&format!("is_async: {}", func.is_async));
46 self.fmt.line(&format!("loc: {}", print::format_loc(&func.loc)));
47
48 self.fmt.line("params:");
50 self.fmt.indent();
51 for (i, param) in func.params.iter().enumerate() {
52 match param {
53 ParamPattern::Place(place) => {
54 self.fmt.format_place_field(&format!("[{}]", i), place);
55 }
56 ParamPattern::Spread(spread) => {
57 self.fmt.line(&format!("[{}] Spread:", i));
58 self.fmt.indent();
59 self.fmt.format_place_field("place", &spread.place);
60 self.fmt.dedent();
61 }
62 }
63 }
64 self.fmt.dedent();
65
66 self.fmt.line("returns:");
68 self.fmt.indent();
69 self.fmt.format_place_field("value", &func.returns);
70 self.fmt.dedent();
71
72 self.fmt.line("context:");
74 self.fmt.indent();
75 for (i, place) in func.context.iter().enumerate() {
76 self.fmt.format_place_field(&format!("[{}]", i), place);
77 }
78 self.fmt.dedent();
79
80 match &func.aliasing_effects {
82 Some(effects) => {
83 self.fmt.line("aliasingEffects:");
84 self.fmt.indent();
85 for (i, eff) in effects.iter().enumerate() {
86 self.fmt.line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));
87 }
88 self.fmt.dedent();
89 }
90 None => self.fmt.line("aliasingEffects: null"),
91 }
92
93 self.fmt.line("directives:");
95 self.fmt.indent();
96 for (i, d) in func.directives.iter().enumerate() {
97 self.fmt.line(&format!("[{}] \"{}\"", i, d));
98 }
99 self.fmt.dedent();
100
101 self.fmt.line(&format!(
103 "returnTypeAnnotation: {}",
104 match &func.return_type_annotation {
105 Some(ann) => ann.clone(),
106 None => "null".to_string(),
107 }
108 ));
109
110 self.fmt.line("");
111 self.fmt.line("Blocks:");
112 self.fmt.indent();
113 for (block_id, block) in &func.body.blocks {
114 self.format_block(block_id, block, &func.instructions);
115 }
116 self.fmt.dedent();
117 self.fmt.dedent();
118 }
119
120 fn format_block(
125 &mut self,
126 block_id: &BlockId,
127 block: &BasicBlock,
128 instructions: &[Instruction],
129 ) {
130 self.fmt.line(&format!("bb{} ({}):", block_id.0, block.kind));
131 self.fmt.indent();
132
133 let preds: Vec<String> = block.preds.iter().map(|p| format!("bb{}", p.0)).collect();
135 self.fmt.line(&format!("preds: [{}]", preds.join(", ")));
136
137 self.fmt.line("phis:");
139 self.fmt.indent();
140 for phi in &block.phis {
141 self.format_phi(phi);
142 }
143 self.fmt.dedent();
144
145 self.fmt.line("instructions:");
147 self.fmt.indent();
148 for (index, instr_id) in block.instructions.iter().enumerate() {
149 let instr = &instructions[instr_id.0 as usize];
150 self.format_instruction(instr, index);
151 }
152 self.fmt.dedent();
153
154 self.fmt.line("terminal:");
156 self.fmt.indent();
157 self.format_terminal(&block.terminal);
158 self.fmt.dedent();
159
160 self.fmt.dedent();
161 }
162
163 fn format_phi(&mut self, phi: &react_compiler_hir::Phi) {
168 self.fmt.line("Phi {");
169 self.fmt.indent();
170 self.fmt.format_place_field("place", &phi.place);
171 self.fmt.line("operands:");
172 self.fmt.indent();
173 for (block_id, place) in &phi.operands {
174 self.fmt.line(&format!("bb{}:", block_id.0));
175 self.fmt.indent();
176 self.fmt.format_place_field("value", place);
177 self.fmt.dedent();
178 }
179 self.fmt.dedent();
180 self.fmt.dedent();
181 self.fmt.line("}");
182 }
183
184 fn format_instruction(&mut self, instr: &Instruction, index: usize) {
189 self.fmt.line(&format!("[{}] Instruction {{", index));
190 self.fmt.indent();
191 self.fmt.line(&format!("id: {}", instr.id.0));
192 self.fmt.format_place_field("lvalue", &instr.lvalue);
193 self.fmt.line("value:");
194 self.fmt.indent();
195 self.fmt.format_instruction_value(
197 &instr.value,
198 Some(&|fmt: &mut PrintFormatter, func: &HirFunction| {
199 let mut inner = DebugPrinter {
202 fmt: PrintFormatter {
203 env: fmt.env,
204 seen_identifiers: std::mem::take(&mut fmt.seen_identifiers),
205 seen_scopes: std::mem::take(&mut fmt.seen_scopes),
206 output: Vec::new(),
207 indent_level: fmt.indent_level,
208 },
209 };
210 inner.format_function(func);
211 for line in &inner.fmt.output {
213 fmt.line_raw(line);
214 }
215 fmt.seen_identifiers = inner.fmt.seen_identifiers;
217 fmt.seen_scopes = inner.fmt.seen_scopes;
218 }),
219 );
220 self.fmt.dedent();
221 match &instr.effects {
222 Some(effects) => {
223 self.fmt.line("effects:");
224 self.fmt.indent();
225 for (i, eff) in effects.iter().enumerate() {
226 self.fmt.line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));
227 }
228 self.fmt.dedent();
229 }
230 None => self.fmt.line("effects: null"),
231 }
232 self.fmt.line(&format!("loc: {}", print::format_loc(&instr.loc)));
233 self.fmt.dedent();
234 self.fmt.line("}");
235 }
236
237 fn format_terminal(&mut self, terminal: &Terminal) {
242 match terminal {
243 Terminal::If {
244 test,
245 consequent,
246 alternate,
247 fallthrough,
248 id,
249 loc,
250 } => {
251 self.fmt.line("If {");
252 self.fmt.indent();
253 self.fmt.line(&format!("id: {}", id.0));
254 self.fmt.format_place_field("test", test);
255 self.fmt.line(&format!("consequent: bb{}", consequent.0));
256 self.fmt.line(&format!("alternate: bb{}", alternate.0));
257 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
258 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
259 self.fmt.dedent();
260 self.fmt.line("}");
261 }
262 Terminal::Branch {
263 test,
264 consequent,
265 alternate,
266 fallthrough,
267 id,
268 loc,
269 } => {
270 self.fmt.line("Branch {");
271 self.fmt.indent();
272 self.fmt.line(&format!("id: {}", id.0));
273 self.fmt.format_place_field("test", test);
274 self.fmt.line(&format!("consequent: bb{}", consequent.0));
275 self.fmt.line(&format!("alternate: bb{}", alternate.0));
276 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
277 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
278 self.fmt.dedent();
279 self.fmt.line("}");
280 }
281 Terminal::Logical {
282 operator,
283 test,
284 fallthrough,
285 id,
286 loc,
287 } => {
288 self.fmt.line("Logical {");
289 self.fmt.indent();
290 self.fmt.line(&format!("id: {}", id.0));
291 self.fmt.line(&format!("operator: \"{}\"", operator));
292 self.fmt.line(&format!("test: bb{}", test.0));
293 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
294 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
295 self.fmt.dedent();
296 self.fmt.line("}");
297 }
298 Terminal::Ternary {
299 test,
300 fallthrough,
301 id,
302 loc,
303 } => {
304 self.fmt.line("Ternary {");
305 self.fmt.indent();
306 self.fmt.line(&format!("id: {}", id.0));
307 self.fmt.line(&format!("test: bb{}", test.0));
308 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
309 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
310 self.fmt.dedent();
311 self.fmt.line("}");
312 }
313 Terminal::Optional {
314 optional,
315 test,
316 fallthrough,
317 id,
318 loc,
319 } => {
320 self.fmt.line("Optional {");
321 self.fmt.indent();
322 self.fmt.line(&format!("id: {}", id.0));
323 self.fmt.line(&format!("optional: {}", optional));
324 self.fmt.line(&format!("test: bb{}", test.0));
325 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
326 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
327 self.fmt.dedent();
328 self.fmt.line("}");
329 }
330 Terminal::Throw { value, id, loc } => {
331 self.fmt.line("Throw {");
332 self.fmt.indent();
333 self.fmt.line(&format!("id: {}", id.0));
334 self.fmt.format_place_field("value", value);
335 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
336 self.fmt.dedent();
337 self.fmt.line("}");
338 }
339 Terminal::Return {
340 value,
341 return_variant,
342 id,
343 loc,
344 effects,
345 } => {
346 self.fmt.line("Return {");
347 self.fmt.indent();
348 self.fmt.line(&format!("id: {}", id.0));
349 self.fmt.line(&format!("returnVariant: {:?}", return_variant));
350 self.fmt.format_place_field("value", value);
351 match effects {
352 Some(e) => {
353 self.fmt.line("effects:");
354 self.fmt.indent();
355 for (i, eff) in e.iter().enumerate() {
356 self.fmt.line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));
357 }
358 self.fmt.dedent();
359 }
360 None => self.fmt.line("effects: null"),
361 }
362 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
363 self.fmt.dedent();
364 self.fmt.line("}");
365 }
366 Terminal::Goto {
367 block,
368 variant,
369 id,
370 loc,
371 } => {
372 self.fmt.line("Goto {");
373 self.fmt.indent();
374 self.fmt.line(&format!("id: {}", id.0));
375 self.fmt.line(&format!("block: bb{}", block.0));
376 self.fmt.line(&format!("variant: {:?}", variant));
377 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
378 self.fmt.dedent();
379 self.fmt.line("}");
380 }
381 Terminal::Switch {
382 test,
383 cases,
384 fallthrough,
385 id,
386 loc,
387 } => {
388 self.fmt.line("Switch {");
389 self.fmt.indent();
390 self.fmt.line(&format!("id: {}", id.0));
391 self.fmt.format_place_field("test", test);
392 self.fmt.line("cases:");
393 self.fmt.indent();
394 for (i, case) in cases.iter().enumerate() {
395 match &case.test {
396 Some(p) => {
397 self.fmt.line(&format!("[{}] Case {{", i));
398 self.fmt.indent();
399 self.fmt.format_place_field("test", p);
400 self.fmt.line(&format!("block: bb{}", case.block.0));
401 self.fmt.dedent();
402 self.fmt.line("}");
403 }
404 None => {
405 self.fmt.line(&format!(
406 "[{}] Default {{ block: bb{} }}",
407 i, case.block.0
408 ));
409 }
410 }
411 }
412 self.fmt.dedent();
413 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
414 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
415 self.fmt.dedent();
416 self.fmt.line("}");
417 }
418 Terminal::DoWhile {
419 loop_block,
420 test,
421 fallthrough,
422 id,
423 loc,
424 } => {
425 self.fmt.line("DoWhile {");
426 self.fmt.indent();
427 self.fmt.line(&format!("id: {}", id.0));
428 self.fmt.line(&format!("loop: bb{}", loop_block.0));
429 self.fmt.line(&format!("test: bb{}", test.0));
430 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
431 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
432 self.fmt.dedent();
433 self.fmt.line("}");
434 }
435 Terminal::While {
436 test,
437 loop_block,
438 fallthrough,
439 id,
440 loc,
441 } => {
442 self.fmt.line("While {");
443 self.fmt.indent();
444 self.fmt.line(&format!("id: {}", id.0));
445 self.fmt.line(&format!("test: bb{}", test.0));
446 self.fmt.line(&format!("loop: bb{}", loop_block.0));
447 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
448 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
449 self.fmt.dedent();
450 self.fmt.line("}");
451 }
452 Terminal::For {
453 init,
454 test,
455 update,
456 loop_block,
457 fallthrough,
458 id,
459 loc,
460 } => {
461 self.fmt.line("For {");
462 self.fmt.indent();
463 self.fmt.line(&format!("id: {}", id.0));
464 self.fmt.line(&format!("init: bb{}", init.0));
465 self.fmt.line(&format!("test: bb{}", test.0));
466 self.fmt.line(&format!(
467 "update: {}",
468 match update {
469 Some(u) => format!("bb{}", u.0),
470 None => "null".to_string(),
471 }
472 ));
473 self.fmt.line(&format!("loop: bb{}", loop_block.0));
474 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
475 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
476 self.fmt.dedent();
477 self.fmt.line("}");
478 }
479 Terminal::ForOf {
480 init,
481 test,
482 loop_block,
483 fallthrough,
484 id,
485 loc,
486 } => {
487 self.fmt.line("ForOf {");
488 self.fmt.indent();
489 self.fmt.line(&format!("id: {}", id.0));
490 self.fmt.line(&format!("init: bb{}", init.0));
491 self.fmt.line(&format!("test: bb{}", test.0));
492 self.fmt.line(&format!("loop: bb{}", loop_block.0));
493 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
494 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
495 self.fmt.dedent();
496 self.fmt.line("}");
497 }
498 Terminal::ForIn {
499 init,
500 loop_block,
501 fallthrough,
502 id,
503 loc,
504 } => {
505 self.fmt.line("ForIn {");
506 self.fmt.indent();
507 self.fmt.line(&format!("id: {}", id.0));
508 self.fmt.line(&format!("init: bb{}", init.0));
509 self.fmt.line(&format!("loop: bb{}", loop_block.0));
510 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
511 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
512 self.fmt.dedent();
513 self.fmt.line("}");
514 }
515 Terminal::Label {
516 block,
517 fallthrough,
518 id,
519 loc,
520 } => {
521 self.fmt.line("Label {");
522 self.fmt.indent();
523 self.fmt.line(&format!("id: {}", id.0));
524 self.fmt.line(&format!("block: bb{}", block.0));
525 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
526 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
527 self.fmt.dedent();
528 self.fmt.line("}");
529 }
530 Terminal::Sequence {
531 block,
532 fallthrough,
533 id,
534 loc,
535 } => {
536 self.fmt.line("Sequence {");
537 self.fmt.indent();
538 self.fmt.line(&format!("id: {}", id.0));
539 self.fmt.line(&format!("block: bb{}", block.0));
540 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
541 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
542 self.fmt.dedent();
543 self.fmt.line("}");
544 }
545 Terminal::Unreachable { id, loc } => {
546 self.fmt.line(&format!(
547 "Unreachable {{ id: {}, loc: {} }}",
548 id.0,
549 print::format_loc(loc)
550 ));
551 }
552 Terminal::Unsupported { id, loc } => {
553 self.fmt.line(&format!(
554 "Unsupported {{ id: {}, loc: {} }}",
555 id.0,
556 print::format_loc(loc)
557 ));
558 }
559 Terminal::MaybeThrow {
560 continuation,
561 handler,
562 id,
563 loc,
564 effects,
565 } => {
566 self.fmt.line("MaybeThrow {");
567 self.fmt.indent();
568 self.fmt.line(&format!("id: {}", id.0));
569 self.fmt.line(&format!("continuation: bb{}", continuation.0));
570 self.fmt.line(&format!(
571 "handler: {}",
572 match handler {
573 Some(h) => format!("bb{}", h.0),
574 None => "null".to_string(),
575 }
576 ));
577 match effects {
578 Some(e) => {
579 self.fmt.line("effects:");
580 self.fmt.indent();
581 for (i, eff) in e.iter().enumerate() {
582 self.fmt.line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));
583 }
584 self.fmt.dedent();
585 }
586 None => self.fmt.line("effects: null"),
587 }
588 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
589 self.fmt.dedent();
590 self.fmt.line("}");
591 }
592 Terminal::Scope {
593 fallthrough,
594 block,
595 scope,
596 id,
597 loc,
598 } => {
599 self.fmt.line("Scope {");
600 self.fmt.indent();
601 self.fmt.line(&format!("id: {}", id.0));
602 self.fmt.format_scope_field("scope", *scope);
603 self.fmt.line(&format!("block: bb{}", block.0));
604 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
605 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
606 self.fmt.dedent();
607 self.fmt.line("}");
608 }
609 Terminal::PrunedScope {
610 fallthrough,
611 block,
612 scope,
613 id,
614 loc,
615 } => {
616 self.fmt.line("PrunedScope {");
617 self.fmt.indent();
618 self.fmt.line(&format!("id: {}", id.0));
619 self.fmt.format_scope_field("scope", *scope);
620 self.fmt.line(&format!("block: bb{}", block.0));
621 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
622 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
623 self.fmt.dedent();
624 self.fmt.line("}");
625 }
626 Terminal::Try {
627 block,
628 handler_binding,
629 handler,
630 fallthrough,
631 id,
632 loc,
633 } => {
634 self.fmt.line("Try {");
635 self.fmt.indent();
636 self.fmt.line(&format!("id: {}", id.0));
637 self.fmt.line(&format!("block: bb{}", block.0));
638 self.fmt.line(&format!("handler: bb{}", handler.0));
639 match handler_binding {
640 Some(p) => self.fmt.format_place_field("handlerBinding", p),
641 None => self.fmt.line("handlerBinding: null"),
642 }
643 self.fmt.line(&format!("fallthrough: bb{}", fallthrough.0));
644 self.fmt.line(&format!("loc: {}", print::format_loc(loc)));
645 self.fmt.dedent();
646 self.fmt.line("}");
647 }
648 }
649 }
650}
651
652pub fn debug_hir(hir: &HirFunction, env: &Environment) -> String {
657 let mut printer = DebugPrinter::new(env);
658 printer.format_function(hir);
659
660 for outlined in env.get_outlined_functions() {
662 printer.fmt.line("");
663 printer.format_function(&outlined.func);
664 }
665
666 printer.fmt.line("");
667 printer.fmt.line("Environment:");
668 printer.fmt.indent();
669 printer.fmt.format_errors(&env.errors);
670 printer.fmt.dedent();
671
672 printer.fmt.to_string_output()
673}
674
675pub fn format_errors(error: &CompilerError) -> String {
680 let env = Environment::new();
681 let mut fmt = PrintFormatter::new(&env);
682 fmt.format_errors(error);
683 fmt.to_string_output()
684}
685
686pub fn format_hir_function_into(
690 reactive_fmt: &mut PrintFormatter,
691 func: &HirFunction,
692) {
693 let mut printer = DebugPrinter {
695 fmt: PrintFormatter {
696 env: reactive_fmt.env,
697 seen_identifiers: std::mem::take(&mut reactive_fmt.seen_identifiers),
698 seen_scopes: std::mem::take(&mut reactive_fmt.seen_scopes),
699 output: Vec::new(),
700 indent_level: reactive_fmt.indent_level,
701 },
702 };
703 printer.format_function(func);
704
705 for line in &printer.fmt.output {
707 reactive_fmt.line_raw(line);
708 }
709 reactive_fmt.seen_identifiers = printer.fmt.seen_identifiers;
711 reactive_fmt.seen_scopes = printer.fmt.seen_scopes;
712}
713
714#[allow(dead_code)]
719fn format_place_short(place: &Place, env: &Environment) -> String {
720 let ident = &env.identifiers[place.identifier.0 as usize];
721 let name = match &ident.name {
722 Some(name) => name.value().to_string(),
723 None => String::new(),
724 };
725 let scope = match ident.scope {
726 Some(scope_id) => format!(":{}", scope_id.0),
727 None => String::new(),
728 };
729 format!("{}${}{}", name, place.identifier.0, scope)
730}