1use std::collections::HashSet;
12
13use react_compiler_diagnostics::CompilerError;
14use react_compiler_diagnostics::CompilerErrorOrDiagnostic;
15use react_compiler_diagnostics::SourceLocation;
16
17use crate::AliasingEffect;
18use crate::HirFunction;
19use crate::IdentifierId;
20use crate::IdentifierName;
21use crate::InstructionValue;
22use crate::LValue;
23use crate::MutationReason;
24use crate::Pattern;
25use crate::Place;
26use crate::PlaceOrSpreadOrHole;
27use crate::ScopeId;
28use crate::Type;
29use crate::environment::Environment;
30use crate::type_config::ValueKind;
31use crate::type_config::ValueReason;
32
33pub fn format_loc(loc: &Option<SourceLocation>) -> String {
38 match loc {
39 Some(l) => format_loc_value(l),
40 None => "generated".to_string(),
41 }
42}
43
44pub fn format_loc_value(loc: &SourceLocation) -> String {
45 format!(
46 "{}:{}-{}:{}",
47 loc.start.line, loc.start.column, loc.end.line, loc.end.column
48 )
49}
50
51pub fn format_js_string(s: &str) -> String {
54 let mut result = String::with_capacity(s.len() + 2);
55 result.push('"');
56 for c in s.chars() {
57 match c {
58 '"' => result.push_str("\\\""),
59 '\\' => result.push_str("\\\\"),
60 '\n' => result.push_str("\\n"),
61 '\r' => result.push_str("\\r"),
62 '\t' => result.push_str("\\t"),
63 '\u{0008}' => result.push_str("\\b"),
64 '\u{000c}' => result.push_str("\\f"),
65 c if (c as u32) <= 0x1F => {
68 result.push_str(&format!("\\u{:04x}", c as u32));
69 }
70 c => result.push(c),
71 }
72 }
73 result.push('"');
74 result
75 }
76
77pub fn format_primitive(prim: &crate::PrimitiveValue) -> String {
78 match prim {
79 crate::PrimitiveValue::Null => "null".to_string(),
80 crate::PrimitiveValue::Undefined => "undefined".to_string(),
81 crate::PrimitiveValue::Boolean(b) => format!("{}", b),
82 crate::PrimitiveValue::Number(n) => crate::format_js_number(n.value()),
83 crate::PrimitiveValue::String(s) => format_js_string(s),
84 }
85}
86
87pub fn format_property_literal(prop: &crate::PropertyLiteral) -> String {
88 match prop {
89 crate::PropertyLiteral::String(s) => s.clone(),
90 crate::PropertyLiteral::Number(n) => crate::format_js_number(n.value()),
91 }
92}
93
94pub fn format_object_property_key(key: &crate::ObjectPropertyKey) -> String {
95 match key {
96 crate::ObjectPropertyKey::String { name } => format!("String(\"{}\")", name),
97 crate::ObjectPropertyKey::Identifier { name } => {
98 format!("Identifier(\"{}\")", name)
99 }
100 crate::ObjectPropertyKey::Computed { name } => {
101 format!("Computed({})", name.identifier.0)
102 }
103 crate::ObjectPropertyKey::Number { name } => {
104 format!("Number({})", crate::format_js_number(name.value()))
105 }
106 }
107}
108
109pub fn format_non_local_binding(binding: &crate::NonLocalBinding) -> String {
110 match binding {
111 crate::NonLocalBinding::Global { name } => {
112 format!("Global {{ name: \"{}\" }}", name)
113 }
114 crate::NonLocalBinding::ModuleLocal { name } => {
115 format!("ModuleLocal {{ name: \"{}\" }}", name)
116 }
117 crate::NonLocalBinding::ImportDefault { name, module } => {
118 format!(
119 "ImportDefault {{ name: \"{}\", module: \"{}\" }}",
120 name, module
121 )
122 }
123 crate::NonLocalBinding::ImportNamespace { name, module } => {
124 format!(
125 "ImportNamespace {{ name: \"{}\", module: \"{}\" }}",
126 name, module
127 )
128 }
129 crate::NonLocalBinding::ImportSpecifier {
130 name,
131 module,
132 imported,
133 } => {
134 format!(
135 "ImportSpecifier {{ name: \"{}\", module: \"{}\", imported: \"{}\" }}",
136 name, module, imported
137 )
138 }
139 }
140}
141
142pub fn format_value_kind(kind: ValueKind) -> &'static str {
143 match kind {
144 ValueKind::Mutable => "mutable",
145 ValueKind::Frozen => "frozen",
146 ValueKind::Primitive => "primitive",
147 ValueKind::MaybeFrozen => "maybe-frozen",
148 ValueKind::Global => "global",
149 ValueKind::Context => "context",
150 }
151}
152
153pub fn format_value_reason(reason: ValueReason) -> &'static str {
154 match reason {
155 ValueReason::KnownReturnSignature => "known-return-signature",
156 ValueReason::State => "state",
157 ValueReason::ReducerState => "reducer-state",
158 ValueReason::Context => "context",
159 ValueReason::Effect => "effect",
160 ValueReason::HookCaptured => "hook-captured",
161 ValueReason::HookReturn => "hook-return",
162 ValueReason::Global => "global",
163 ValueReason::JsxCaptured => "jsx-captured",
164 ValueReason::StoreLocal => "store-local",
165 ValueReason::ReactiveFunctionArgument => "reactive-function-argument",
166 ValueReason::Other => "other",
167 }
168}
169
170pub struct PrintFormatter<'a> {
179 pub env: &'a Environment,
180 pub seen_identifiers: HashSet<IdentifierId>,
181 pub seen_scopes: HashSet<ScopeId>,
182 pub output: Vec<String>,
183 pub indent_level: usize,
184}
185
186impl<'a> PrintFormatter<'a> {
187 pub fn new(env: &'a Environment) -> Self {
188 Self {
189 env,
190 seen_identifiers: HashSet::new(),
191 seen_scopes: HashSet::new(),
192 output: Vec::new(),
193 indent_level: 0,
194 }
195 }
196
197 pub fn line(&mut self, text: &str) {
198 let indent = " ".repeat(self.indent_level);
199 self.output.push(format!("{}{}", indent, text));
200 }
201
202 pub fn line_raw(&mut self, text: &str) {
204 self.output.push(text.to_string());
205 }
206
207 pub fn indent(&mut self) {
208 self.indent_level += 1;
209 }
210
211 pub fn dedent(&mut self) {
212 self.indent_level -= 1;
213 }
214
215 pub fn to_string_output(&self) -> String {
216 self.output.join("\n")
217 }
218
219 pub fn format_effect(&self, effect: &AliasingEffect) -> String {
224 match effect {
225 AliasingEffect::Freeze { value, reason } => {
226 format!(
227 "Freeze {{ value: {}, reason: {} }}",
228 value.identifier.0,
229 format_value_reason(*reason)
230 )
231 }
232 AliasingEffect::Mutate { value, reason } => match reason {
233 Some(MutationReason::AssignCurrentProperty) => {
234 format!(
235 "Mutate {{ value: {}, reason: AssignCurrentProperty }}",
236 value.identifier.0
237 )
238 }
239 None => format!("Mutate {{ value: {} }}", value.identifier.0),
240 },
241 AliasingEffect::MutateConditionally { value } => {
242 format!("MutateConditionally {{ value: {} }}", value.identifier.0)
243 }
244 AliasingEffect::MutateTransitive { value } => {
245 format!("MutateTransitive {{ value: {} }}", value.identifier.0)
246 }
247 AliasingEffect::MutateTransitiveConditionally { value } => {
248 format!(
249 "MutateTransitiveConditionally {{ value: {} }}",
250 value.identifier.0
251 )
252 }
253 AliasingEffect::Capture { from, into } => {
254 format!(
255 "Capture {{ into: {}, from: {} }}",
256 into.identifier.0, from.identifier.0
257 )
258 }
259 AliasingEffect::Alias { from, into } => {
260 format!(
261 "Alias {{ into: {}, from: {} }}",
262 into.identifier.0, from.identifier.0
263 )
264 }
265 AliasingEffect::MaybeAlias { from, into } => {
266 format!(
267 "MaybeAlias {{ into: {}, from: {} }}",
268 into.identifier.0, from.identifier.0
269 )
270 }
271 AliasingEffect::Assign { from, into } => {
272 format!(
273 "Assign {{ into: {}, from: {} }}",
274 into.identifier.0, from.identifier.0
275 )
276 }
277 AliasingEffect::Create {
278 into,
279 value,
280 reason,
281 } => {
282 format!(
283 "Create {{ into: {}, value: {}, reason: {} }}",
284 into.identifier.0,
285 format_value_kind(*value),
286 format_value_reason(*reason)
287 )
288 }
289 AliasingEffect::CreateFrom { from, into } => {
290 format!(
291 "CreateFrom {{ into: {}, from: {} }}",
292 into.identifier.0, from.identifier.0
293 )
294 }
295 AliasingEffect::ImmutableCapture { from, into } => {
296 format!(
297 "ImmutableCapture {{ into: {}, from: {} }}",
298 into.identifier.0, from.identifier.0
299 )
300 }
301 AliasingEffect::Apply {
302 receiver,
303 function,
304 mutates_function,
305 args,
306 into,
307 ..
308 } => {
309 let args_str: Vec<String> = args
310 .iter()
311 .map(|a| match a {
312 PlaceOrSpreadOrHole::Hole => "hole".to_string(),
313 PlaceOrSpreadOrHole::Place(p) => p.identifier.0.to_string(),
314 PlaceOrSpreadOrHole::Spread(s) => format!("...{}", s.place.identifier.0),
315 })
316 .collect();
317 format!(
318 "Apply {{ into: {}, receiver: {}, function: {}, mutatesFunction: {}, args: [{}] }}",
319 into.identifier.0,
320 receiver.identifier.0,
321 function.identifier.0,
322 mutates_function,
323 args_str.join(", ")
324 )
325 }
326 AliasingEffect::CreateFunction {
327 captures,
328 function_id: _,
329 into,
330 } => {
331 let cap_str: Vec<String> = captures
332 .iter()
333 .map(|p| p.identifier.0.to_string())
334 .collect();
335 format!(
336 "CreateFunction {{ into: {}, captures: [{}] }}",
337 into.identifier.0,
338 cap_str.join(", ")
339 )
340 }
341 AliasingEffect::MutateFrozen { place, error } => {
342 format!(
343 "MutateFrozen {{ place: {}, reason: {:?} }}",
344 place.identifier.0, error.reason
345 )
346 }
347 AliasingEffect::MutateGlobal { place, error } => {
348 format!(
349 "MutateGlobal {{ place: {}, reason: {:?} }}",
350 place.identifier.0, error.reason
351 )
352 }
353 AliasingEffect::Impure { place, error } => {
354 format!(
355 "Impure {{ place: {}, reason: {:?} }}",
356 place.identifier.0, error.reason
357 )
358 }
359 AliasingEffect::Render { place } => {
360 format!("Render {{ place: {} }}", place.identifier.0)
361 }
362 }
363 }
364
365 pub fn format_place_field(&mut self, field_name: &str, place: &Place) {
370 let is_seen = self.seen_identifiers.contains(&place.identifier);
371 if is_seen {
372 self.line(&format!(
373 "{}: Place {{ identifier: Identifier({}), effect: {}, reactive: {}, loc: {} }}",
374 field_name,
375 place.identifier.0,
376 place.effect,
377 place.reactive,
378 format_loc(&place.loc)
379 ));
380 } else {
381 self.line(&format!("{}: Place {{", field_name));
382 self.indent();
383 self.line("identifier:");
384 self.indent();
385 self.format_identifier(place.identifier);
386 self.dedent();
387 self.line(&format!("effect: {}", place.effect));
388 self.line(&format!("reactive: {}", place.reactive));
389 self.line(&format!("loc: {}", format_loc(&place.loc)));
390 self.dedent();
391 self.line("}");
392 }
393 }
394
395 pub fn format_identifier(&mut self, id: IdentifierId) {
400 self.seen_identifiers.insert(id);
401 let ident = &self.env.identifiers[id.0 as usize];
402 self.line("Identifier {");
403 self.indent();
404 self.line(&format!("id: {}", ident.id.0));
405 self.line(&format!("declarationId: {}", ident.declaration_id.0));
406 match &ident.name {
407 Some(name) => {
408 let (kind, value) = match name {
409 IdentifierName::Named(n) => ("named", n.as_str()),
410 IdentifierName::Promoted(n) => ("promoted", n.as_str()),
411 };
412 self.line(&format!(
413 "name: {{ kind: \"{}\", value: \"{}\" }}",
414 kind, value
415 ));
416 }
417 None => self.line("name: null"),
418 }
419 self.line(&format!(
429 "mutableRange: [{}:{}]",
430 ident.mutable_range.start.0, ident.mutable_range.end.0
431 ));
432 match ident.scope {
433 Some(scope_id) => self.format_scope_field("scope", scope_id),
434 None => self.line("scope: null"),
435 }
436 self.line(&format!("type: {}", self.format_type(ident.type_)));
437 self.line(&format!("loc: {}", format_loc(&ident.loc)));
438 self.dedent();
439 self.line("}");
440 }
441
442 pub fn format_scope_field(&mut self, field_name: &str, scope_id: ScopeId) {
447 let is_seen = self.seen_scopes.contains(&scope_id);
448 if is_seen {
449 self.line(&format!("{}: Scope({})", field_name, scope_id.0));
450 } else {
451 self.seen_scopes.insert(scope_id);
452 if let Some(scope) = self.env.scopes.iter().find(|s| s.id == scope_id) {
453 let range_start = scope.range.start.0;
454 let range_end = scope.range.end.0;
455 let dependencies = scope.dependencies.clone();
456 let declarations = scope.declarations.clone();
457 let reassignments = scope.reassignments.clone();
458 let early_return_value = scope.early_return_value.clone();
459 let merged = scope.merged.clone();
460 let loc = scope.loc;
461
462 self.line(&format!("{}: Scope {{", field_name));
463 self.indent();
464 self.line(&format!("id: {}", scope_id.0));
465 self.line(&format!("range: [{}:{}]", range_start, range_end));
466
467 self.line("dependencies:");
469 self.indent();
470 for (i, dep) in dependencies.iter().enumerate() {
471 let path_str: String = dep
472 .path
473 .iter()
474 .map(|p| {
475 let prop = match &p.property {
476 crate::PropertyLiteral::String(s) => s.clone(),
477 crate::PropertyLiteral::Number(n) => {
478 crate::format_js_number(n.value())
479 }
480 };
481 format!("{}{}", if p.optional { "?." } else { "." }, prop)
482 })
483 .collect();
484 self.line(&format!(
485 "[{}] {{ identifier: {}, reactive: {}, path: \"{}\" }}",
486 i, dep.identifier.0, dep.reactive, path_str
487 ));
488 }
489 self.dedent();
490
491 self.line("declarations:");
493 self.indent();
494 for (ident_id, decl) in &declarations {
495 self.line(&format!(
496 "{}: {{ identifier: {}, scope: {} }}",
497 ident_id.0, decl.identifier.0, decl.scope.0
498 ));
499 }
500 self.dedent();
501
502 self.line("reassignments:");
504 self.indent();
505 for ident_id in &reassignments {
506 self.line(&format!("{}", ident_id.0));
507 }
508 self.dedent();
509
510 if let Some(early_return) = &early_return_value {
512 self.line("earlyReturnValue:");
513 self.indent();
514 self.line(&format!("value: {}", early_return.value.0));
515 self.line(&format!("loc: {}", format_loc(&early_return.loc)));
516 self.line(&format!("label: bb{}", early_return.label.0));
517 self.dedent();
518 } else {
519 self.line("earlyReturnValue: null");
520 }
521
522 let merged_str: Vec<String> = merged.iter().map(|s| s.0.to_string()).collect();
524 self.line(&format!("merged: [{}]", merged_str.join(", ")));
525
526 self.line(&format!("loc: {}", format_loc(&loc)));
528
529 self.dedent();
530 self.line("}");
531 } else {
532 self.line(&format!("{}: Scope({})", field_name, scope_id.0));
533 }
534 }
535 }
536
537 pub fn format_type(&self, type_id: crate::TypeId) -> String {
542 if let Some(ty) = self.env.types.get(type_id.0 as usize) {
543 self.format_type_value(ty)
544 } else {
545 format!("Type({})", type_id.0)
546 }
547 }
548
549 pub fn format_type_value(&self, ty: &Type) -> String {
550 match ty {
551 Type::Primitive => "Primitive".to_string(),
552 Type::Function {
553 shape_id,
554 return_type,
555 is_constructor,
556 } => {
557 format!(
558 "Function {{ shapeId: {}, return: {}, isConstructor: {} }}",
559 match shape_id {
560 Some(s) => format!("\"{}\"", s),
561 None => "null".to_string(),
562 },
563 self.format_type_value(return_type),
564 is_constructor
565 )
566 }
567 Type::Object { shape_id } => {
568 format!(
569 "Object {{ shapeId: {} }}",
570 match shape_id {
571 Some(s) => format!("\"{}\"", s),
572 None => "null".to_string(),
573 }
574 )
575 }
576 Type::TypeVar { id } => format!("Type({})", id.0),
577 Type::Poly => "Poly".to_string(),
578 Type::Phi { operands } => {
579 let ops: Vec<String> = operands
580 .iter()
581 .map(|op| self.format_type_value(op))
582 .collect();
583 format!("Phi {{ operands: [{}] }}", ops.join(", "))
584 }
585 Type::Property {
586 object_type,
587 object_name,
588 property_name,
589 } => {
590 let prop_str = match property_name {
591 crate::PropertyNameKind::Literal { value } => {
592 format!("\"{}\"", format_property_literal(value))
593 }
594 crate::PropertyNameKind::Computed { value } => {
595 format!("computed({})", self.format_type_value(value))
596 }
597 };
598 format!(
599 "Property {{ objectType: {}, objectName: \"{}\", propertyName: {} }}",
600 self.format_type_value(object_type),
601 object_name,
602 prop_str
603 )
604 }
605 Type::ObjectMethod => "ObjectMethod".to_string(),
606 }
607 }
608
609 pub fn format_lvalue(&mut self, field_name: &str, lv: &LValue) {
614 self.line(&format!("{}:", field_name));
615 self.indent();
616 self.line(&format!("kind: {:?}", lv.kind));
617 self.format_place_field("place", &lv.place);
618 self.dedent();
619 }
620
621 pub fn format_pattern(&mut self, pattern: &Pattern) {
626 match pattern {
627 Pattern::Array(arr) => {
628 self.line("pattern: ArrayPattern {");
629 self.indent();
630 self.line("items:");
631 self.indent();
632 for (i, item) in arr.items.iter().enumerate() {
633 match item {
634 crate::ArrayPatternElement::Hole => {
635 self.line(&format!("[{}] Hole", i));
636 }
637 crate::ArrayPatternElement::Place(p) => {
638 self.format_place_field(&format!("[{}]", i), p);
639 }
640 crate::ArrayPatternElement::Spread(s) => {
641 self.line(&format!("[{}] Spread:", i));
642 self.indent();
643 self.format_place_field("place", &s.place);
644 self.dedent();
645 }
646 }
647 }
648 self.dedent();
649 self.line(&format!("loc: {}", format_loc(&arr.loc)));
650 self.dedent();
651 self.line("}");
652 }
653 Pattern::Object(obj) => {
654 self.line("pattern: ObjectPattern {");
655 self.indent();
656 self.line("properties:");
657 self.indent();
658 for (i, prop) in obj.properties.iter().enumerate() {
659 match prop {
660 crate::ObjectPropertyOrSpread::Property(p) => {
661 self.line(&format!("[{}] ObjectProperty {{", i));
662 self.indent();
663 self.line(&format!("key: {}", format_object_property_key(&p.key)));
664 self.line(&format!("type: \"{}\"", p.property_type));
665 self.format_place_field("place", &p.place);
666 self.dedent();
667 self.line("}");
668 }
669 crate::ObjectPropertyOrSpread::Spread(s) => {
670 self.line(&format!("[{}] Spread:", i));
671 self.indent();
672 self.format_place_field("place", &s.place);
673 self.dedent();
674 }
675 }
676 }
677 self.dedent();
678 self.line(&format!("loc: {}", format_loc(&obj.loc)));
679 self.dedent();
680 self.line("}");
681 }
682 }
683 }
684
685 pub fn format_argument(&mut self, arg: &crate::PlaceOrSpread, index: usize) {
690 match arg {
691 crate::PlaceOrSpread::Place(p) => {
692 self.format_place_field(&format!("[{}]", index), p);
693 }
694 crate::PlaceOrSpread::Spread(s) => {
695 self.line(&format!("[{}] Spread:", index));
696 self.indent();
697 self.format_place_field("place", &s.place);
698 self.dedent();
699 }
700 }
701 }
702
703 pub fn format_instruction_value(
711 &mut self,
712 value: &InstructionValue,
713 inner_func_formatter: Option<&dyn Fn(&mut PrintFormatter, &HirFunction)>,
714 ) {
715 match value {
716 InstructionValue::ArrayExpression { elements, loc } => {
717 self.line("ArrayExpression {");
718 self.indent();
719 self.line("elements:");
720 self.indent();
721 for (i, elem) in elements.iter().enumerate() {
722 match elem {
723 crate::ArrayElement::Place(p) => {
724 self.format_place_field(&format!("[{}]", i), p);
725 }
726 crate::ArrayElement::Hole => {
727 self.line(&format!("[{}] Hole", i));
728 }
729 crate::ArrayElement::Spread(s) => {
730 self.line(&format!("[{}] Spread:", i));
731 self.indent();
732 self.format_place_field("place", &s.place);
733 self.dedent();
734 }
735 }
736 }
737 self.dedent();
738 self.line(&format!("loc: {}", format_loc(loc)));
739 self.dedent();
740 self.line("}");
741 }
742 InstructionValue::ObjectExpression { properties, loc } => {
743 self.line("ObjectExpression {");
744 self.indent();
745 self.line("properties:");
746 self.indent();
747 for (i, prop) in properties.iter().enumerate() {
748 match prop {
749 crate::ObjectPropertyOrSpread::Property(p) => {
750 self.line(&format!("[{}] ObjectProperty {{", i));
751 self.indent();
752 self.line(&format!("key: {}", format_object_property_key(&p.key)));
753 self.line(&format!("type: \"{}\"", p.property_type));
754 self.format_place_field("place", &p.place);
755 self.dedent();
756 self.line("}");
757 }
758 crate::ObjectPropertyOrSpread::Spread(s) => {
759 self.line(&format!("[{}] Spread:", i));
760 self.indent();
761 self.format_place_field("place", &s.place);
762 self.dedent();
763 }
764 }
765 }
766 self.dedent();
767 self.line(&format!("loc: {}", format_loc(loc)));
768 self.dedent();
769 self.line("}");
770 }
771 InstructionValue::UnaryExpression {
772 operator,
773 value: val,
774 loc,
775 } => {
776 self.line("UnaryExpression {");
777 self.indent();
778 self.line(&format!("operator: \"{}\"", operator));
779 self.format_place_field("value", val);
780 self.line(&format!("loc: {}", format_loc(loc)));
781 self.dedent();
782 self.line("}");
783 }
784 InstructionValue::BinaryExpression {
785 operator,
786 left,
787 right,
788 loc,
789 } => {
790 self.line("BinaryExpression {");
791 self.indent();
792 self.line(&format!("operator: \"{}\"", operator));
793 self.format_place_field("left", left);
794 self.format_place_field("right", right);
795 self.line(&format!("loc: {}", format_loc(loc)));
796 self.dedent();
797 self.line("}");
798 }
799 InstructionValue::NewExpression { callee, args, loc } => {
800 self.line("NewExpression {");
801 self.indent();
802 self.format_place_field("callee", callee);
803 self.line("args:");
804 self.indent();
805 for (i, arg) in args.iter().enumerate() {
806 self.format_argument(arg, i);
807 }
808 self.dedent();
809 self.line(&format!("loc: {}", format_loc(loc)));
810 self.dedent();
811 self.line("}");
812 }
813 InstructionValue::CallExpression { callee, args, loc } => {
814 self.line("CallExpression {");
815 self.indent();
816 self.format_place_field("callee", callee);
817 self.line("args:");
818 self.indent();
819 for (i, arg) in args.iter().enumerate() {
820 self.format_argument(arg, i);
821 }
822 self.dedent();
823 self.line(&format!("loc: {}", format_loc(loc)));
824 self.dedent();
825 self.line("}");
826 }
827 InstructionValue::MethodCall {
828 receiver,
829 property,
830 args,
831 loc,
832 } => {
833 self.line("MethodCall {");
834 self.indent();
835 self.format_place_field("receiver", receiver);
836 self.format_place_field("property", property);
837 self.line("args:");
838 self.indent();
839 for (i, arg) in args.iter().enumerate() {
840 self.format_argument(arg, i);
841 }
842 self.dedent();
843 self.line(&format!("loc: {}", format_loc(loc)));
844 self.dedent();
845 self.line("}");
846 }
847 InstructionValue::JSXText { value: val, loc } => {
848 self.line(&format!(
849 "JSXText {{ value: {}, loc: {} }}",
850 format_js_string(val),
851 format_loc(loc)
852 ));
853 }
854 InstructionValue::Primitive { value: prim, loc } => {
855 self.line(&format!(
856 "Primitive {{ value: {}, loc: {} }}",
857 format_primitive(prim),
858 format_loc(loc)
859 ));
860 }
861 InstructionValue::TypeCastExpression {
862 value: val,
863 type_,
864 type_annotation_name,
865 type_annotation_kind,
866 type_annotation: _,
867 loc,
868 } => {
869 self.line("TypeCastExpression {");
870 self.indent();
871 self.format_place_field("value", val);
872 self.line(&format!("type: {}", self.format_type_value(type_)));
873 if let Some(annotation_name) = type_annotation_name {
874 self.line(&format!("typeAnnotation: {}", annotation_name));
875 }
876 if let Some(annotation_kind) = type_annotation_kind {
877 self.line(&format!("typeAnnotationKind: \"{}\"", annotation_kind));
878 }
879 self.line(&format!("loc: {}", format_loc(loc)));
880 self.dedent();
881 self.line("}");
882 }
883 InstructionValue::JsxExpression {
884 tag,
885 props,
886 children,
887 loc,
888 opening_loc,
889 closing_loc,
890 } => {
891 self.line("JsxExpression {");
892 self.indent();
893 match tag {
894 crate::JsxTag::Place(p) => {
895 self.format_place_field("tag", p);
896 }
897 crate::JsxTag::Builtin(b) => {
898 self.line(&format!("tag: BuiltinTag(\"{}\")", b.name));
899 }
900 }
901 self.line("props:");
902 self.indent();
903 for (i, prop) in props.iter().enumerate() {
904 match prop {
905 crate::JsxAttribute::Attribute { name, place } => {
906 self.line(&format!("[{}] JsxAttribute {{", i));
907 self.indent();
908 self.line(&format!("name: \"{}\"", name));
909 self.format_place_field("place", place);
910 self.dedent();
911 self.line("}");
912 }
913 crate::JsxAttribute::SpreadAttribute { argument } => {
914 self.line(&format!("[{}] JsxSpreadAttribute:", i));
915 self.indent();
916 self.format_place_field("argument", argument);
917 self.dedent();
918 }
919 }
920 }
921 self.dedent();
922 match children {
923 Some(c) => {
924 self.line("children:");
925 self.indent();
926 for (i, child) in c.iter().enumerate() {
927 self.format_place_field(&format!("[{}]", i), child);
928 }
929 self.dedent();
930 }
931 None => self.line("children: null"),
932 }
933 self.line(&format!("openingLoc: {}", format_loc(opening_loc)));
934 self.line(&format!("closingLoc: {}", format_loc(closing_loc)));
935 self.line(&format!("loc: {}", format_loc(loc)));
936 self.dedent();
937 self.line("}");
938 }
939 InstructionValue::JsxFragment { children, loc } => {
940 self.line("JsxFragment {");
941 self.indent();
942 self.line("children:");
943 self.indent();
944 for (i, child) in children.iter().enumerate() {
945 self.format_place_field(&format!("[{}]", i), child);
946 }
947 self.dedent();
948 self.line(&format!("loc: {}", format_loc(loc)));
949 self.dedent();
950 self.line("}");
951 }
952 InstructionValue::UnsupportedNode { node_type, loc, .. } => match node_type {
953 Some(t) => self.line(&format!(
954 "UnsupportedNode {{ type: {:?}, loc: {} }}",
955 t,
956 format_loc(loc)
957 )),
958 None => self.line(&format!("UnsupportedNode {{ loc: {} }}", format_loc(loc))),
959 },
960 InstructionValue::LoadLocal { place, loc } => {
961 self.line("LoadLocal {");
962 self.indent();
963 self.format_place_field("place", place);
964 self.line(&format!("loc: {}", format_loc(loc)));
965 self.dedent();
966 self.line("}");
967 }
968 InstructionValue::DeclareLocal {
969 lvalue,
970 type_annotation,
971 loc,
972 } => {
973 self.line("DeclareLocal {");
974 self.indent();
975 self.format_lvalue("lvalue", lvalue);
976 self.line(&format!(
977 "type: {}",
978 match type_annotation {
979 Some(t) => t.clone(),
980 None => "null".to_string(),
981 }
982 ));
983 self.line(&format!("loc: {}", format_loc(loc)));
984 self.dedent();
985 self.line("}");
986 }
987 InstructionValue::DeclareContext { lvalue, loc } => {
988 self.line("DeclareContext {");
989 self.indent();
990 self.line("lvalue:");
991 self.indent();
992 self.line(&format!("kind: {:?}", lvalue.kind));
993 self.format_place_field("place", &lvalue.place);
994 self.dedent();
995 self.line(&format!("loc: {}", format_loc(loc)));
996 self.dedent();
997 self.line("}");
998 }
999 InstructionValue::StoreLocal {
1000 lvalue,
1001 value: val,
1002 type_annotation,
1003 loc,
1004 } => {
1005 self.line("StoreLocal {");
1006 self.indent();
1007 self.format_lvalue("lvalue", lvalue);
1008 self.format_place_field("value", val);
1009 self.line(&format!(
1010 "type: {}",
1011 match type_annotation {
1012 Some(t) => t.clone(),
1013 None => "null".to_string(),
1014 }
1015 ));
1016 self.line(&format!("loc: {}", format_loc(loc)));
1017 self.dedent();
1018 self.line("}");
1019 }
1020 InstructionValue::LoadContext { place, loc } => {
1021 self.line("LoadContext {");
1022 self.indent();
1023 self.format_place_field("place", place);
1024 self.line(&format!("loc: {}", format_loc(loc)));
1025 self.dedent();
1026 self.line("}");
1027 }
1028 InstructionValue::StoreContext {
1029 lvalue,
1030 value: val,
1031 loc,
1032 } => {
1033 self.line("StoreContext {");
1034 self.indent();
1035 self.line("lvalue:");
1036 self.indent();
1037 self.line(&format!("kind: {:?}", lvalue.kind));
1038 self.format_place_field("place", &lvalue.place);
1039 self.dedent();
1040 self.format_place_field("value", val);
1041 self.line(&format!("loc: {}", format_loc(loc)));
1042 self.dedent();
1043 self.line("}");
1044 }
1045 InstructionValue::Destructure {
1046 lvalue,
1047 value: val,
1048 loc,
1049 } => {
1050 self.line("Destructure {");
1051 self.indent();
1052 self.line("lvalue:");
1053 self.indent();
1054 self.line(&format!("kind: {:?}", lvalue.kind));
1055 self.format_pattern(&lvalue.pattern);
1056 self.dedent();
1057 self.format_place_field("value", val);
1058 self.line(&format!("loc: {}", format_loc(loc)));
1059 self.dedent();
1060 self.line("}");
1061 }
1062 InstructionValue::PropertyLoad {
1063 object,
1064 property,
1065 loc,
1066 } => {
1067 self.line("PropertyLoad {");
1068 self.indent();
1069 self.format_place_field("object", object);
1070 self.line(&format!(
1071 "property: \"{}\"",
1072 format_property_literal(property)
1073 ));
1074 self.line(&format!("loc: {}", format_loc(loc)));
1075 self.dedent();
1076 self.line("}");
1077 }
1078 InstructionValue::PropertyStore {
1079 object,
1080 property,
1081 value: val,
1082 loc,
1083 } => {
1084 self.line("PropertyStore {");
1085 self.indent();
1086 self.format_place_field("object", object);
1087 self.line(&format!(
1088 "property: \"{}\"",
1089 format_property_literal(property)
1090 ));
1091 self.format_place_field("value", val);
1092 self.line(&format!("loc: {}", format_loc(loc)));
1093 self.dedent();
1094 self.line("}");
1095 }
1096 InstructionValue::PropertyDelete {
1097 object,
1098 property,
1099 loc,
1100 } => {
1101 self.line("PropertyDelete {");
1102 self.indent();
1103 self.format_place_field("object", object);
1104 self.line(&format!(
1105 "property: \"{}\"",
1106 format_property_literal(property)
1107 ));
1108 self.line(&format!("loc: {}", format_loc(loc)));
1109 self.dedent();
1110 self.line("}");
1111 }
1112 InstructionValue::ComputedLoad {
1113 object,
1114 property,
1115 loc,
1116 } => {
1117 self.line("ComputedLoad {");
1118 self.indent();
1119 self.format_place_field("object", object);
1120 self.format_place_field("property", property);
1121 self.line(&format!("loc: {}", format_loc(loc)));
1122 self.dedent();
1123 self.line("}");
1124 }
1125 InstructionValue::ComputedStore {
1126 object,
1127 property,
1128 value: val,
1129 loc,
1130 } => {
1131 self.line("ComputedStore {");
1132 self.indent();
1133 self.format_place_field("object", object);
1134 self.format_place_field("property", property);
1135 self.format_place_field("value", val);
1136 self.line(&format!("loc: {}", format_loc(loc)));
1137 self.dedent();
1138 self.line("}");
1139 }
1140 InstructionValue::ComputedDelete {
1141 object,
1142 property,
1143 loc,
1144 } => {
1145 self.line("ComputedDelete {");
1146 self.indent();
1147 self.format_place_field("object", object);
1148 self.format_place_field("property", property);
1149 self.line(&format!("loc: {}", format_loc(loc)));
1150 self.dedent();
1151 self.line("}");
1152 }
1153 InstructionValue::LoadGlobal { binding, loc } => {
1154 self.line("LoadGlobal {");
1155 self.indent();
1156 self.line(&format!("binding: {}", format_non_local_binding(binding)));
1157 self.line(&format!("loc: {}", format_loc(loc)));
1158 self.dedent();
1159 self.line("}");
1160 }
1161 InstructionValue::StoreGlobal {
1162 name,
1163 value: val,
1164 loc,
1165 } => {
1166 self.line("StoreGlobal {");
1167 self.indent();
1168 self.line(&format!("name: \"{}\"", name));
1169 self.format_place_field("value", val);
1170 self.line(&format!("loc: {}", format_loc(loc)));
1171 self.dedent();
1172 self.line("}");
1173 }
1174 InstructionValue::FunctionExpression {
1175 name,
1176 name_hint,
1177 lowered_func,
1178 expr_type,
1179 loc,
1180 } => {
1181 self.line("FunctionExpression {");
1182 self.indent();
1183 self.line(&format!(
1184 "name: {}",
1185 match name {
1186 Some(n) => format!("\"{}\"", n),
1187 None => "null".to_string(),
1188 }
1189 ));
1190 self.line(&format!(
1191 "nameHint: {}",
1192 match name_hint {
1193 Some(h) => format!("\"{}\"", h),
1194 None => "null".to_string(),
1195 }
1196 ));
1197 self.line(&format!("type: \"{:?}\"", expr_type));
1198 self.line("loweredFunc:");
1199 let inner_func = &self.env.functions[lowered_func.func.0 as usize];
1200 if let Some(formatter) = inner_func_formatter {
1201 formatter(self, inner_func);
1202 } else {
1203 self.line(&format!(" <function {}>", lowered_func.func.0));
1204 }
1205 self.line(&format!("loc: {}", format_loc(loc)));
1206 self.dedent();
1207 self.line("}");
1208 }
1209 InstructionValue::ObjectMethod { loc, lowered_func } => {
1210 self.line("ObjectMethod {");
1211 self.indent();
1212 self.line("loweredFunc:");
1213 let inner_func = &self.env.functions[lowered_func.func.0 as usize];
1214 if let Some(formatter) = inner_func_formatter {
1215 formatter(self, inner_func);
1216 } else {
1217 self.line(&format!(" <function {}>", lowered_func.func.0));
1218 }
1219 self.line(&format!("loc: {}", format_loc(loc)));
1220 self.dedent();
1221 self.line("}");
1222 }
1223 InstructionValue::TaggedTemplateExpression {
1224 tag,
1225 value: val,
1226 loc,
1227 } => {
1228 self.line("TaggedTemplateExpression {");
1229 self.indent();
1230 self.format_place_field("tag", tag);
1231 self.line(&format!("raw: {}", format_js_string(&val.raw)));
1232 self.line(&format!(
1233 "cooked: {}",
1234 match &val.cooked {
1235 Some(c) => format_js_string(c),
1236 None => "undefined".to_string(),
1237 }
1238 ));
1239 self.line(&format!("loc: {}", format_loc(loc)));
1240 self.dedent();
1241 self.line("}");
1242 }
1243 InstructionValue::TemplateLiteral {
1244 subexprs,
1245 quasis,
1246 loc,
1247 } => {
1248 self.line("TemplateLiteral {");
1249 self.indent();
1250 self.line("subexprs:");
1251 self.indent();
1252 for (i, sub) in subexprs.iter().enumerate() {
1253 self.format_place_field(&format!("[{}]", i), sub);
1254 }
1255 self.dedent();
1256 self.line("quasis:");
1257 self.indent();
1258 for (i, q) in quasis.iter().enumerate() {
1259 self.line(&format!(
1260 "[{}] {{ raw: {}, cooked: {} }}",
1261 i,
1262 format_js_string(&q.raw),
1263 match &q.cooked {
1264 Some(c) => format_js_string(c),
1265 None => "undefined".to_string(),
1266 }
1267 ));
1268 }
1269 self.dedent();
1270 self.line(&format!("loc: {}", format_loc(loc)));
1271 self.dedent();
1272 self.line("}");
1273 }
1274 InstructionValue::RegExpLiteral {
1275 pattern,
1276 flags,
1277 loc,
1278 } => {
1279 self.line(&format!(
1280 "RegExpLiteral {{ pattern: \"{}\", flags: \"{}\", loc: {} }}",
1281 pattern,
1282 flags,
1283 format_loc(loc)
1284 ));
1285 }
1286 InstructionValue::MetaProperty {
1287 meta,
1288 property,
1289 loc,
1290 } => {
1291 self.line(&format!(
1292 "MetaProperty {{ meta: \"{}\", property: \"{}\", loc: {} }}",
1293 meta,
1294 property,
1295 format_loc(loc)
1296 ));
1297 }
1298 InstructionValue::Await { value: val, loc } => {
1299 self.line("Await {");
1300 self.indent();
1301 self.format_place_field("value", val);
1302 self.line(&format!("loc: {}", format_loc(loc)));
1303 self.dedent();
1304 self.line("}");
1305 }
1306 InstructionValue::GetIterator { collection, loc } => {
1307 self.line("GetIterator {");
1308 self.indent();
1309 self.format_place_field("collection", collection);
1310 self.line(&format!("loc: {}", format_loc(loc)));
1311 self.dedent();
1312 self.line("}");
1313 }
1314 InstructionValue::IteratorNext {
1315 iterator,
1316 collection,
1317 loc,
1318 } => {
1319 self.line("IteratorNext {");
1320 self.indent();
1321 self.format_place_field("iterator", iterator);
1322 self.format_place_field("collection", collection);
1323 self.line(&format!("loc: {}", format_loc(loc)));
1324 self.dedent();
1325 self.line("}");
1326 }
1327 InstructionValue::NextPropertyOf { value: val, loc } => {
1328 self.line("NextPropertyOf {");
1329 self.indent();
1330 self.format_place_field("value", val);
1331 self.line(&format!("loc: {}", format_loc(loc)));
1332 self.dedent();
1333 self.line("}");
1334 }
1335 InstructionValue::Debugger { loc } => {
1336 self.line(&format!("Debugger {{ loc: {} }}", format_loc(loc)));
1337 }
1338 InstructionValue::PostfixUpdate {
1339 lvalue,
1340 operation,
1341 value: val,
1342 loc,
1343 } => {
1344 self.line("PostfixUpdate {");
1345 self.indent();
1346 self.format_place_field("lvalue", lvalue);
1347 self.line(&format!("operation: \"{}\"", operation));
1348 self.format_place_field("value", val);
1349 self.line(&format!("loc: {}", format_loc(loc)));
1350 self.dedent();
1351 self.line("}");
1352 }
1353 InstructionValue::PrefixUpdate {
1354 lvalue,
1355 operation,
1356 value: val,
1357 loc,
1358 } => {
1359 self.line("PrefixUpdate {");
1360 self.indent();
1361 self.format_place_field("lvalue", lvalue);
1362 self.line(&format!("operation: \"{}\"", operation));
1363 self.format_place_field("value", val);
1364 self.line(&format!("loc: {}", format_loc(loc)));
1365 self.dedent();
1366 self.line("}");
1367 }
1368 InstructionValue::StartMemoize {
1369 manual_memo_id,
1370 deps,
1371 deps_loc: _,
1372 has_invalid_deps: _,
1373 loc,
1374 } => {
1375 self.line("StartMemoize {");
1376 self.indent();
1377 self.line(&format!("manualMemoId: {}", manual_memo_id));
1378 match deps {
1379 Some(d) => {
1380 self.line("deps:");
1381 self.indent();
1382 for (i, dep) in d.iter().enumerate() {
1383 let root_str = match &dep.root {
1384 crate::ManualMemoDependencyRoot::Global { identifier_name } => {
1385 format!("Global(\"{}\")", identifier_name)
1386 }
1387 crate::ManualMemoDependencyRoot::NamedLocal {
1388 value: val,
1389 constant,
1390 } => {
1391 format!(
1392 "NamedLocal({}, constant={})",
1393 val.identifier.0, constant
1394 )
1395 }
1396 };
1397 let path_str: String = dep
1398 .path
1399 .iter()
1400 .map(|p| {
1401 format!(
1402 "{}.{}",
1403 if p.optional { "?" } else { "" },
1404 format_property_literal(&p.property)
1405 )
1406 })
1407 .collect();
1408 self.line(&format!("[{}] {}{}", i, root_str, path_str));
1409 }
1410 self.dedent();
1411 }
1412 None => self.line("deps: null"),
1413 }
1414 self.line(&format!("loc: {}", format_loc(loc)));
1415 self.dedent();
1416 self.line("}");
1417 }
1418 InstructionValue::FinishMemoize {
1419 manual_memo_id,
1420 decl,
1421 pruned,
1422 loc,
1423 } => {
1424 self.line("FinishMemoize {");
1425 self.indent();
1426 self.line(&format!("manualMemoId: {}", manual_memo_id));
1427 self.format_place_field("decl", decl);
1428 self.line(&format!("pruned: {}", pruned));
1429 self.line(&format!("loc: {}", format_loc(loc)));
1430 self.dedent();
1431 self.line("}");
1432 }
1433 }
1434 }
1435
1436 pub fn format_errors(&mut self, error: &CompilerError) {
1441 if error.details.is_empty() {
1442 self.line("Errors: []");
1443 return;
1444 }
1445 self.line("Errors:");
1446 self.indent();
1447 for (i, detail) in error.details.iter().enumerate() {
1448 self.line(&format!("[{}] {{", i));
1449 self.indent();
1450 match detail {
1451 CompilerErrorOrDiagnostic::Diagnostic(d) => {
1452 self.line(&format!("severity: {:?}", d.severity()));
1453 self.line(&format!("reason: {:?}", d.reason));
1454 self.line(&format!(
1455 "description: {}",
1456 match &d.description {
1457 Some(desc) => format!("{:?}", desc),
1458 None => "null".to_string(),
1459 }
1460 ));
1461 self.line(&format!("category: {:?}", d.category));
1462 let loc = d.primary_location();
1463 self.line(&format!(
1464 "loc: {}",
1465 match loc {
1466 Some(l) => format_loc_value(l),
1467 None => "null".to_string(),
1468 }
1469 ));
1470 }
1471 CompilerErrorOrDiagnostic::ErrorDetail(d) => {
1472 self.line(&format!("severity: {:?}", d.severity()));
1473 self.line(&format!("reason: {:?}", d.reason));
1474 self.line(&format!(
1475 "description: {}",
1476 match &d.description {
1477 Some(desc) => format!("{:?}", desc),
1478 None => "null".to_string(),
1479 }
1480 ));
1481 self.line(&format!("category: {:?}", d.category));
1482 self.line(&format!(
1483 "loc: {}",
1484 match &d.loc {
1485 Some(l) => format_loc_value(l),
1486 None => "null".to_string(),
1487 }
1488 ));
1489 }
1490 }
1491 self.dedent();
1492 self.line("}");
1493 }
1494 self.dedent();
1495 }
1496}