use super::error::DecompileError;
use super::options::DebugOptions;
use super::state::{DecompileContext, DecompileStage, DecompileState, StageDebugOutput};
struct StageDescriptor {
stage: DecompileStage,
run: for<'a> fn(&mut DecompileState, &DecompileContext<'a>) -> Result<(), DecompileError>,
dump: fn(&DecompileState, &DebugOptions) -> Result<StageDebugOutput, DecompileError>,
}
const PIPELINE_STAGES: &[StageDescriptor] = &[
StageDescriptor {
stage: DecompileStage::Parse,
run: crate::parser::parse_input,
dump: crate::parser::dump_parser,
},
StageDescriptor {
stage: DecompileStage::Transform,
run: crate::transformer::lower_chunk,
dump: crate::transformer::dump_lir,
},
StageDescriptor {
stage: DecompileStage::Cfg,
run: crate::cfg::build_cfg_proto,
dump: crate::cfg::dump_cfg,
},
StageDescriptor {
stage: DecompileStage::GraphFacts,
run: crate::cfg::analyze_graph_facts,
dump: crate::cfg::dump_graph_facts,
},
StageDescriptor {
stage: DecompileStage::Dataflow,
run: crate::cfg::analyze_dataflow,
dump: crate::cfg::dump_dataflow,
},
StageDescriptor {
stage: DecompileStage::StructureFacts,
run: crate::structure::analyze_structure,
dump: crate::structure::dump_structure,
},
StageDescriptor {
stage: DecompileStage::Hir,
run: crate::hir::analyze_hir,
dump: crate::hir::dump_hir,
},
StageDescriptor {
stage: DecompileStage::Ast,
run: crate::ast::lower_ast_for_generate,
dump: crate::ast::dump_ast,
},
StageDescriptor {
stage: DecompileStage::Readability,
run: crate::ast::make_readable,
dump: crate::ast::dump_readability,
},
StageDescriptor {
stage: DecompileStage::Naming,
run: crate::naming::assign_names,
dump: crate::naming::dump_naming,
},
StageDescriptor {
stage: DecompileStage::Generate,
run: crate::generate::generate_chunk,
dump: crate::generate::dump_generate,
},
];
pub(super) fn run_decompile_stages(
state: &mut DecompileState,
context: &DecompileContext<'_>,
debug_output: &mut Vec<StageDebugOutput>,
) -> Result<(), DecompileError> {
for descriptor in PIPELINE_STAGES {
{
let _timing = context
.timings
.scope(<&'static str>::from(descriptor.stage));
(descriptor.run)(state, context)?;
state.mark_completed(descriptor.stage);
}
if context.options.debug.enable
&& context
.options
.debug
.output_stages
.contains(&descriptor.stage)
{
debug_output.push((descriptor.dump)(state, &context.options.debug)?);
}
if descriptor.stage == context.options.target_stage {
break;
}
}
Ok(())
}