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