compiler/crates/react_compiler_reactive_scopes/src/print_reactive_function.rs RUST 632 lines View on github.com → Search inside
1// Copyright (c) Meta Platforms, Inc. and affiliates.2//3// This source code is licensed under the MIT license found in the4// LICENSE file in the root directory of this source tree.56//! Verbose debug printer for ReactiveFunction.7//!8//! Produces output identical to the TS `printDebugReactiveFunction`.9//! Delegates shared formatting (Places, Identifiers, Scopes, Types,10//! InstructionValues, Effects, Errors) to `react_compiler_hir::print::PrintFormatter`.1112use react_compiler_hir::environment::Environment;13use react_compiler_hir::print::{self, PrintFormatter};14use react_compiler_hir::{15    HirFunction, ParamPattern, ReactiveBlock, ReactiveFunction, ReactiveInstruction,16    ReactiveStatement, ReactiveTerminal, ReactiveTerminalStatement, ReactiveValue,17};1819// =============================================================================20// DebugPrinter — thin wrapper around PrintFormatter for reactive-specific logic21// =============================================================================2223pub struct DebugPrinter<'a> {24    pub fmt: PrintFormatter<'a>,25    /// Optional formatter for HIR functions (used for inner functions in FunctionExpression/ObjectMethod)26    pub hir_formatter: Option<&'a HirFunctionFormatter>,27}2829impl<'a> DebugPrinter<'a> {30    pub fn new(env: &'a Environment) -> Self {31        Self {32            fmt: PrintFormatter::new(env),33            hir_formatter: None,34        }35    }3637    // =========================================================================38    // ReactiveFunction39    // =========================================================================4041    pub fn format_reactive_function(&mut self, func: &ReactiveFunction) {42        self.fmt.indent();43        self.fmt.line(&format!(44            "id: {}",45            match &func.id {46                Some(id) => format!("\"{}\"", id),47                None => "null".to_string(),48            }49        ));50        self.fmt.line(&format!(51            "name_hint: {}",52            match &func.name_hint {53                Some(h) => format!("\"{}\"", h),54                None => "null".to_string(),55            }56        ));57        self.fmt.line(&format!("generator: {}", func.generator));58        self.fmt.line(&format!("is_async: {}", func.is_async));59        self.fmt60            .line(&format!("loc: {}", print::format_loc(&func.loc)));6162        // params63        self.fmt.line("params:");64        self.fmt.indent();65        for (i, param) in func.params.iter().enumerate() {66            match param {67                ParamPattern::Place(place) => {68                    self.fmt.format_place_field(&format!("[{}]", i), place);69                }70                ParamPattern::Spread(spread) => {71                    self.fmt.line(&format!("[{}] Spread:", i));72                    self.fmt.indent();73                    self.fmt.format_place_field("place", &spread.place);74                    self.fmt.dedent();75                }76            }77        }78        self.fmt.dedent();7980        // directives81        self.fmt.line("directives:");82        self.fmt.indent();83        for (i, d) in func.directives.iter().enumerate() {84            self.fmt.line(&format!("[{}] \"{}\"", i, d));85        }86        self.fmt.dedent();8788        self.fmt.line("");89        self.fmt.line("Body:");90        self.fmt.indent();91        self.format_reactive_block(&func.body);92        self.fmt.dedent();93        self.fmt.dedent();94    }9596    // =========================================================================97    // ReactiveBlock98    // =========================================================================99100    fn format_reactive_block(&mut self, block: &ReactiveBlock) {101        for stmt in block.iter() {102            self.format_reactive_statement(stmt);103        }104    }105106    fn format_reactive_statement(&mut self, stmt: &ReactiveStatement) {107        match stmt {108            ReactiveStatement::Instruction(instr) => {109                self.format_reactive_instruction_block(instr);110            }111            ReactiveStatement::Terminal(term) => {112                self.fmt.line("ReactiveTerminalStatement {");113                self.fmt.indent();114                self.format_terminal_statement(term);115                self.fmt.dedent();116                self.fmt.line("}");117            }118            ReactiveStatement::Scope(scope) => {119                self.fmt.line("ReactiveScopeBlock {");120                self.fmt.indent();121                self.fmt.format_scope_field("scope", scope.scope);122                self.fmt.line("instructions:");123                self.fmt.indent();124                self.format_reactive_block(&scope.instructions);125                self.fmt.dedent();126                self.fmt.dedent();127                self.fmt.line("}");128            }129            ReactiveStatement::PrunedScope(scope) => {130                self.fmt.line("PrunedReactiveScopeBlock {");131                self.fmt.indent();132                self.fmt.format_scope_field("scope", scope.scope);133                self.fmt.line("instructions:");134                self.fmt.indent();135                self.format_reactive_block(&scope.instructions);136                self.fmt.dedent();137                self.fmt.dedent();138                self.fmt.line("}");139            }140        }141    }142143    // =========================================================================144    // ReactiveInstruction145    // =========================================================================146147    fn format_reactive_instruction_block(&mut self, instr: &ReactiveInstruction) {148        self.fmt.line("ReactiveInstruction {");149        self.fmt.indent();150        self.format_reactive_instruction(instr);151        self.fmt.dedent();152        self.fmt.line("}");153    }154155    fn format_reactive_instruction(&mut self, instr: &ReactiveInstruction) {156        self.fmt.line(&format!("id: {}", instr.id.0));157        match &instr.lvalue {158            Some(place) => self.fmt.format_place_field("lvalue", place),159            None => self.fmt.line("lvalue: null"),160        }161        self.fmt.line("value:");162        self.fmt.indent();163        self.format_reactive_value(&instr.value);164        self.fmt.dedent();165        match &instr.effects {166            Some(effects) => {167                self.fmt.line("effects:");168                self.fmt.indent();169                for (i, eff) in effects.iter().enumerate() {170                    self.fmt171                        .line(&format!("[{}] {}", i, self.fmt.format_effect(eff)));172                }173                self.fmt.dedent();174            }175            None => self.fmt.line("effects: null"),176        }177        self.fmt178            .line(&format!("loc: {}", print::format_loc(&instr.loc)));179    }180181    // =========================================================================182    // ReactiveValue183    // =========================================================================184185    fn format_reactive_value(&mut self, value: &ReactiveValue) {186        match value {187            ReactiveValue::Instruction(iv) => {188                // Build the inner function formatter callback if we have an hir_formatter189                let hir_formatter = self.hir_formatter;190                let inner_func_cb: Option<Box<dyn Fn(&mut PrintFormatter, &HirFunction) + '_>> =191                    hir_formatter.map(|hf| {192                        Box::new(move |fmt: &mut PrintFormatter, func: &HirFunction| {193                            hf(fmt, func);194                        })195                            as Box<dyn Fn(&mut PrintFormatter, &HirFunction) + '_>196                    });197                self.fmt.format_instruction_value(198                    iv,199                    inner_func_cb200                        .as_ref()201                        .map(|cb| cb.as_ref() as &dyn Fn(&mut PrintFormatter, &HirFunction)),202                );203            }204            ReactiveValue::LogicalExpression {205                operator,206                left,207                right,208                loc,209            } => {210                self.fmt.line("LogicalExpression {");211                self.fmt.indent();212                self.fmt.line(&format!("operator: \"{}\"", operator));213                self.fmt.line("left:");214                self.fmt.indent();215                self.format_reactive_value(left);216                self.fmt.dedent();217                self.fmt.line("right:");218                self.fmt.indent();219                self.format_reactive_value(right);220                self.fmt.dedent();221                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));222                self.fmt.dedent();223                self.fmt.line("}");224            }225            ReactiveValue::ConditionalExpression {226                test,227                consequent,228                alternate,229                loc,230            } => {231                self.fmt.line("ConditionalExpression {");232                self.fmt.indent();233                self.fmt.line("test:");234                self.fmt.indent();235                self.format_reactive_value(test);236                self.fmt.dedent();237                self.fmt.line("consequent:");238                self.fmt.indent();239                self.format_reactive_value(consequent);240                self.fmt.dedent();241                self.fmt.line("alternate:");242                self.fmt.indent();243                self.format_reactive_value(alternate);244                self.fmt.dedent();245                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));246                self.fmt.dedent();247                self.fmt.line("}");248            }249            ReactiveValue::SequenceExpression {250                instructions,251                id,252                value,253                loc,254            } => {255                self.fmt.line("SequenceExpression {");256                self.fmt.indent();257                self.fmt.line("instructions:");258                self.fmt.indent();259                for (i, instr) in instructions.iter().enumerate() {260                    self.fmt.line(&format!("[{}]:", i));261                    self.fmt.indent();262                    self.format_reactive_instruction_block(instr);263                    self.fmt.dedent();264                }265                self.fmt.dedent();266                self.fmt.line(&format!("id: {}", id.0));267                self.fmt.line("value:");268                self.fmt.indent();269                self.format_reactive_value(value);270                self.fmt.dedent();271                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));272                self.fmt.dedent();273                self.fmt.line("}");274            }275            ReactiveValue::OptionalExpression {276                id,277                value,278                optional,279                loc,280            } => {281                self.fmt.line("OptionalExpression {");282                self.fmt.indent();283                self.fmt.line(&format!("id: {}", id.0));284                self.fmt.line("value:");285                self.fmt.indent();286                self.format_reactive_value(value);287                self.fmt.dedent();288                self.fmt.line(&format!("optional: {}", optional));289                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));290                self.fmt.dedent();291                self.fmt.line("}");292            }293        }294    }295296    // =========================================================================297    // ReactiveTerminal298    // =========================================================================299300    fn format_terminal_statement(&mut self, stmt: &ReactiveTerminalStatement) {301        match &stmt.label {302            Some(label) => {303                self.fmt.line(&format!(304                    "label: {{ id: bb{}, implicit: {} }}",305                    label.id.0, label.implicit306                ));307            }308            None => self.fmt.line("label: null"),309        }310        self.fmt.line("terminal:");311        self.fmt.indent();312        self.format_reactive_terminal(&stmt.terminal);313        self.fmt.dedent();314    }315316    fn format_reactive_terminal(&mut self, terminal: &ReactiveTerminal) {317        match terminal {318            ReactiveTerminal::Break {319                target,320                id,321                target_kind,322                loc,323            } => {324                self.fmt.line("Break {");325                self.fmt.indent();326                self.fmt.line(&format!("target: bb{}", target.0));327                self.fmt.line(&format!("id: {}", id.0));328                self.fmt.line(&format!("targetKind: \"{}\"", target_kind));329                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));330                self.fmt.dedent();331                self.fmt.line("}");332            }333            ReactiveTerminal::Continue {334                target,335                id,336                target_kind,337                loc,338            } => {339                self.fmt.line("Continue {");340                self.fmt.indent();341                self.fmt.line(&format!("target: bb{}", target.0));342                self.fmt.line(&format!("id: {}", id.0));343                self.fmt.line(&format!("targetKind: \"{}\"", target_kind));344                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));345                self.fmt.dedent();346                self.fmt.line("}");347            }348            ReactiveTerminal::Return { value, id, loc } => {349                self.fmt.line("Return {");350                self.fmt.indent();351                self.fmt.format_place_field("value", value);352                self.fmt.line(&format!("id: {}", id.0));353                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));354                self.fmt.dedent();355                self.fmt.line("}");356            }357            ReactiveTerminal::Throw { value, id, loc } => {358                self.fmt.line("Throw {");359                self.fmt.indent();360                self.fmt.format_place_field("value", value);361                self.fmt.line(&format!("id: {}", id.0));362                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));363                self.fmt.dedent();364                self.fmt.line("}");365            }366            ReactiveTerminal::Switch {367                test,368                cases,369                id,370                loc,371            } => {372                self.fmt.line("Switch {");373                self.fmt.indent();374                self.fmt.format_place_field("test", test);375                self.fmt.line("cases:");376                self.fmt.indent();377                for (i, case) in cases.iter().enumerate() {378                    self.fmt.line(&format!("[{}] {{", i));379                    self.fmt.indent();380                    match &case.test {381                        Some(p) => {382                            self.fmt.format_place_field("test", p);383                        }384                        None => {385                            self.fmt.line("test: null");386                        }387                    }388                    match &case.block {389                        Some(block) => {390                            self.fmt.line("block:");391                            self.fmt.indent();392                            self.format_reactive_block(block);393                            self.fmt.dedent();394                        }395                        None => self.fmt.line("block: undefined"),396                    }397                    self.fmt.dedent();398                    self.fmt.line("}");399                }400                self.fmt.dedent();401                self.fmt.line(&format!("id: {}", id.0));402                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));403                self.fmt.dedent();404                self.fmt.line("}");405            }406            ReactiveTerminal::DoWhile {407                loop_block,408                test,409                id,410                loc,411            } => {412                self.fmt.line("DoWhile {");413                self.fmt.indent();414                self.fmt.line("loop:");415                self.fmt.indent();416                self.format_reactive_block(loop_block);417                self.fmt.dedent();418                self.fmt.line("test:");419                self.fmt.indent();420                self.format_reactive_value(test);421                self.fmt.dedent();422                self.fmt.line(&format!("id: {}", id.0));423                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));424                self.fmt.dedent();425                self.fmt.line("}");426            }427            ReactiveTerminal::While {428                test,429                loop_block,430                id,431                loc,432            } => {433                self.fmt.line("While {");434                self.fmt.indent();435                self.fmt.line("test:");436                self.fmt.indent();437                self.format_reactive_value(test);438                self.fmt.dedent();439                self.fmt.line("loop:");440                self.fmt.indent();441                self.format_reactive_block(loop_block);442                self.fmt.dedent();443                self.fmt.line(&format!("id: {}", id.0));444                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));445                self.fmt.dedent();446                self.fmt.line("}");447            }448            ReactiveTerminal::For {449                init,450                test,451                update,452                loop_block,453                id,454                loc,455            } => {456                self.fmt.line("For {");457                self.fmt.indent();458                self.fmt.line("init:");459                self.fmt.indent();460                self.format_reactive_value(init);461                self.fmt.dedent();462                self.fmt.line("test:");463                self.fmt.indent();464                self.format_reactive_value(test);465                self.fmt.dedent();466                match update {467                    Some(u) => {468                        self.fmt.line("update:");469                        self.fmt.indent();470                        self.format_reactive_value(u);471                        self.fmt.dedent();472                    }473                    None => self.fmt.line("update: null"),474                }475                self.fmt.line("loop:");476                self.fmt.indent();477                self.format_reactive_block(loop_block);478                self.fmt.dedent();479                self.fmt.line(&format!("id: {}", id.0));480                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));481                self.fmt.dedent();482                self.fmt.line("}");483            }484            ReactiveTerminal::ForOf {485                init,486                test,487                loop_block,488                id,489                loc,490            } => {491                self.fmt.line("ForOf {");492                self.fmt.indent();493                self.fmt.line("init:");494                self.fmt.indent();495                self.format_reactive_value(init);496                self.fmt.dedent();497                self.fmt.line("test:");498                self.fmt.indent();499                self.format_reactive_value(test);500                self.fmt.dedent();501                self.fmt.line("loop:");502                self.fmt.indent();503                self.format_reactive_block(loop_block);504                self.fmt.dedent();505                self.fmt.line(&format!("id: {}", id.0));506                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));507                self.fmt.dedent();508                self.fmt.line("}");509            }510            ReactiveTerminal::ForIn {511                init,512                loop_block,513                id,514                loc,515            } => {516                self.fmt.line("ForIn {");517                self.fmt.indent();518                self.fmt.line("init:");519                self.fmt.indent();520                self.format_reactive_value(init);521                self.fmt.dedent();522                self.fmt.line("loop:");523                self.fmt.indent();524                self.format_reactive_block(loop_block);525                self.fmt.dedent();526                self.fmt.line(&format!("id: {}", id.0));527                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));528                self.fmt.dedent();529                self.fmt.line("}");530            }531            ReactiveTerminal::If {532                test,533                consequent,534                alternate,535                id,536                loc,537            } => {538                self.fmt.line("If {");539                self.fmt.indent();540                self.fmt.format_place_field("test", test);541                self.fmt.line("consequent:");542                self.fmt.indent();543                self.format_reactive_block(consequent);544                self.fmt.dedent();545                match alternate {546                    Some(alt) => {547                        self.fmt.line("alternate:");548                        self.fmt.indent();549                        self.format_reactive_block(alt);550                        self.fmt.dedent();551                    }552                    None => self.fmt.line("alternate: null"),553                }554                self.fmt.line(&format!("id: {}", id.0));555                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));556                self.fmt.dedent();557                self.fmt.line("}");558            }559            ReactiveTerminal::Label { block, id, loc } => {560                self.fmt.line("Label {");561                self.fmt.indent();562                self.fmt.line("block:");563                self.fmt.indent();564                self.format_reactive_block(block);565                self.fmt.dedent();566                self.fmt.line(&format!("id: {}", id.0));567                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));568                self.fmt.dedent();569                self.fmt.line("}");570            }571            ReactiveTerminal::Try {572                block,573                handler_binding,574                handler,575                id,576                loc,577            } => {578                self.fmt.line("Try {");579                self.fmt.indent();580                self.fmt.line("block:");581                self.fmt.indent();582                self.format_reactive_block(block);583                self.fmt.dedent();584                match handler_binding {585                    Some(p) => self.fmt.format_place_field("handlerBinding", p),586                    None => self.fmt.line("handlerBinding: null"),587                }588                self.fmt.line("handler:");589                self.fmt.indent();590                self.format_reactive_block(handler);591                self.fmt.dedent();592                self.fmt.line(&format!("id: {}", id.0));593                self.fmt.line(&format!("loc: {}", print::format_loc(loc)));594                self.fmt.dedent();595                self.fmt.line("}");596            }597        }598    }599}600601// =============================================================================602// Entry point603// =============================================================================604605/// Type alias for a function formatter callback that can print HIR functions.606/// Used to format inner functions in FunctionExpression/ObjectMethod values.607pub type HirFunctionFormatter = dyn Fn(&mut PrintFormatter, &HirFunction);608609pub fn debug_reactive_function(func: &ReactiveFunction, env: &Environment) -> String {610    debug_reactive_function_with_formatter(func, env, None)611}612613pub fn debug_reactive_function_with_formatter(614    func: &ReactiveFunction,615    env: &Environment,616    hir_formatter: Option<&HirFunctionFormatter>,617) -> String {618    let mut printer = DebugPrinter::new(env);619    printer.hir_formatter = hir_formatter;620    printer.format_reactive_function(func);621622    // TODO: Print outlined functions when they've been converted to reactive form623624    printer.fmt.line("");625    printer.fmt.line("Environment:");626    printer.fmt.indent();627    printer.fmt.format_errors(&env.errors);628    printer.fmt.dedent();629630    printer.fmt.to_string_output()631}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.