From a111bb69af642b67d460ea4450e9ae1ebe20f16d Mon Sep 17 00:00:00 2001 From: IWANABETHATGUY <17974631+IWANABETHATGUY@users.noreply.github.com> Date: Thu, 19 Sep 2024 06:13:03 +0000 Subject: [PATCH] feat(oxc_wasm): add `verbse` option to `debug_dot` (#5879) 1. Adding a new option to control displaying `implicit error` edge. **verbose** ![image](https://github.com/user-attachments/assets/cef43d5f-25d0-4408-ad4a-34bc633f2821) **disable verbose** ![image](https://github.com/user-attachments/assets/02954103-689c-422c-8ada-5805a39335b7) --- crates/oxc_semantic/src/dot.rs | 32 ++++++++++++++++++++++---------- crates/oxc_wasm/src/lib.rs | 12 ++++++++++-- crates/oxc_wasm/src/options.rs | 10 ++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/crates/oxc_semantic/src/dot.rs b/crates/oxc_semantic/src/dot.rs index ed768038536d3..d97ad8dacf0f0 100644 --- a/crates/oxc_semantic/src/dot.rs +++ b/crates/oxc_semantic/src/dot.rs @@ -7,8 +7,8 @@ use oxc_cfg::{ dot::{Config, Dot}, visit::EdgeRef, }, - BasicBlock, ControlFlowGraph, EdgeType, Instruction, InstructionKind, IterationInstructionKind, - LabeledInstruction, ReturnInstructionKind, + BasicBlock, ControlFlowGraph, EdgeType, ErrorEdgeKind, Instruction, InstructionKind, + IterationInstructionKind, LabeledInstruction, ReturnInstructionKind, }; use oxc_syntax::node::NodeId; @@ -23,15 +23,24 @@ pub trait DebugDot { } #[derive(Clone, Copy)] -pub struct DebugDotContext<'a, 'b>(&'b AstNodes<'a>); +pub struct DebugDotContext<'a, 'b> { + nodes: &'b AstNodes<'a>, + verbose: bool, +} + +impl<'a, 'b> DebugDotContext<'a, 'b> { + pub fn new(nodes: &'b AstNodes<'a>, verbose: bool) -> DebugDotContext<'a, 'b> { + DebugDotContext { nodes, verbose } + } +} impl<'a, 'b> DebugDotContext<'a, 'b> { fn debug_ast_kind(self, id: NodeId) -> String { - self.0.kind(id).debug_name().into_owned() + self.nodes.kind(id).debug_name().into_owned() } fn try_eval_literal(self, id: NodeId) -> Option { - match self.0.kind(id) { + match self.nodes.kind(id) { AstKind::NumericLiteral(lit) => Some(lit.value.to_string()), AstKind::BooleanLiteral(lit) => Some(lit.value.to_string()), AstKind::StringLiteral(lit) => Some(lit.value.to_string()), @@ -44,7 +53,7 @@ impl<'a, 'b> DebugDotContext<'a, 'b> { impl<'a, 'b> From<&'b AstNodes<'a>> for DebugDotContext<'a, 'b> { fn from(value: &'b AstNodes<'a>) -> Self { - Self(value) + Self::new(value, true) } } @@ -57,6 +66,9 @@ impl DebugDot for ControlFlowGraph { &[Config::EdgeNoLabel, Config::NodeNoLabel], &|_graph, edge| { let weight = edge.weight(); + if !ctx.verbose && matches!(weight, EdgeType::Error(ErrorEdgeKind::Implicit)) { + return String::new(); + } let label = format!("label = \"{weight:?}\" "); if matches!(weight, EdgeType::Unreachable) || self.basic_block(edge.source()).unreachable @@ -118,11 +130,11 @@ impl DebugDot for Instruction { } InstructionKind::Break(LabeledInstruction::Labeled) => { let Some(AstKind::BreakStatement(BreakStatement { label: Some(label), .. })) = - self.node_id.map(|id| ctx.0.get_node(id)).map(AstNode::kind) + self.node_id.map(|id| ctx.nodes.get_node(id)).map(AstNode::kind) else { unreachable!( "Expected a label node to be associated with an labeled break instruction. {:?}", - ctx.0.kind(self.node_id.unwrap()) + ctx.nodes.kind(self.node_id.unwrap()) ) }; format!("break <{}>", label.name) @@ -131,11 +143,11 @@ impl DebugDot for Instruction { InstructionKind::Continue(LabeledInstruction::Labeled) => { let Some(AstKind::ContinueStatement(ContinueStatement { label: Some(label), .. - })) = self.node_id.map(|id| ctx.0.get_node(id)).map(AstNode::kind) + })) = self.node_id.map(|id| ctx.nodes.get_node(id)).map(AstNode::kind) else { unreachable!( "Expected a label node to be associated with an labeled continue instruction. {:?}", - ctx.0.kind(self.node_id.unwrap()) + ctx.nodes.kind(self.node_id.unwrap()) ) }; format!("continue <{}>", label.name) diff --git a/crates/oxc_wasm/src/lib.rs b/crates/oxc_wasm/src/lib.rs index e9c42d4d191c5..70eb40a843360 100644 --- a/crates/oxc_wasm/src/lib.rs +++ b/crates/oxc_wasm/src/lib.rs @@ -16,7 +16,10 @@ use oxc::{ diagnostics::Error, minifier::{CompressOptions, Minifier, MinifierOptions}, parser::{ParseOptions, Parser, ParserReturn}, - semantic::{dot::DebugDot, ScopeFlags, ScopeId, ScopeTree, SemanticBuilder, SymbolTable}, + semantic::{ + dot::{DebugDot, DebugDotContext}, + ScopeFlags, ScopeId, ScopeTree, SemanticBuilder, SymbolTable, + }, span::SourceType, transformer::{EnvOptions, Targets, TransformOptions, Transformer}, }; @@ -153,6 +156,7 @@ impl Oxc { transformer: transform_options, codegen: codegen_options, minifier: minifier_options, + control_flow: control_flow_options, } = options; let run_options = run_options.unwrap_or_default(); let parser_options = parser_options.unwrap_or_default(); @@ -160,6 +164,7 @@ impl Oxc { let minifier_options = minifier_options.unwrap_or_default(); let _codegen_options = codegen_options.unwrap_or_default(); let _transform_options = transform_options.unwrap_or_default(); + let control_flow_options = control_flow_options.unwrap_or_default(); let allocator = Allocator::default(); @@ -205,7 +210,10 @@ impl Oxc { .build(&program); self.control_flow_graph = semantic_ret.semantic.cfg().map_or_else(String::default, |cfg| { - cfg.debug_dot(semantic_ret.semantic.nodes().into()) + cfg.debug_dot(DebugDotContext::new( + semantic_ret.semantic.nodes(), + control_flow_options.verbose.unwrap_or_default(), + )) }); if run_options.syntax.unwrap_or_default() { self.save_diagnostics( diff --git a/crates/oxc_wasm/src/options.rs b/crates/oxc_wasm/src/options.rs index 3856a9ca44c10..3c0f8bb32eee1 100644 --- a/crates/oxc_wasm/src/options.rs +++ b/crates/oxc_wasm/src/options.rs @@ -18,6 +18,8 @@ pub struct OxcOptions { pub codegen: Option, #[tsify(optional)] pub minifier: Option, + #[tsify(optional)] + pub control_flow: Option, } #[derive(Debug, Default, Clone, Deserialize, Tsify)] @@ -82,6 +84,14 @@ pub struct OxcCodegenOptions { pub enable_typescript: Option, } +#[derive(Debug, Default, Clone, Deserialize, Tsify)] +#[tsify(from_wasm_abi)] +#[serde(rename_all = "camelCase")] +pub struct OxcControlFlowOptions { + #[tsify(optional)] + pub verbose: Option, +} + #[derive(Debug, Default, Clone, Deserialize, Tsify)] #[tsify(from_wasm_abi)] #[serde(rename_all = "camelCase")]