mod binding_flow;
mod binding_tree;
mod branch_pretty;
mod cleanup;
mod expr_analysis;
mod field_access_sugar;
mod function_sugar;
mod global_decl_pretty;
mod inline_exprs;
mod installer_iife;
mod local_coalesce;
mod loop_header_merge;
mod luajit_goto_safety;
mod materialize_temps;
mod short_circuit_pretty;
mod statement_merge;
mod traverse;
mod visit;
mod walk;
use super::common::{AstModule, AstTargetDialect};
use crate::readability::ReadabilityOptions;
use crate::scheduler::{run_invalidation_loop, InvalidationTag, PassDescriptor, PassPhase};
use crate::timing::TimingCollector;
#[derive(Clone, Copy)]
pub(super) struct ReadabilityContext {
pub target: AstTargetDialect,
pub options: ReadabilityOptions,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum AstInvalidation {
StatementAdjacency,
ControlFlowShape,
ExprShape,
BindingStructure,
TempPresence,
}
impl InvalidationTag for AstInvalidation {
fn all() -> &'static [Self] {
&[
Self::StatementAdjacency,
Self::ControlFlowShape,
Self::ExprShape,
Self::BindingStructure,
Self::TempPresence,
]
}
}
struct ReadabilityPassEntry {
apply: fn(&mut AstModule, ReadabilityContext) -> bool,
}
use AstInvalidation::*;
const PASS_DESCRIPTORS: &[PassDescriptor<AstInvalidation>] = &[
PassDescriptor {
name: "cleanup",
phase: PassPhase::Normal,
depends_on: &[StatementAdjacency, ControlFlowShape, ExprShape, BindingStructure, TempPresence],
invalidates: &[StatementAdjacency],
},
PassDescriptor {
name: "local-coalesce",
phase: PassPhase::Normal,
depends_on: &[StatementAdjacency, ControlFlowShape, BindingStructure],
invalidates: &[StatementAdjacency, BindingStructure],
},
PassDescriptor {
name: "statement-merge",
phase: PassPhase::Normal,
depends_on: &[StatementAdjacency, ControlFlowShape],
invalidates: &[StatementAdjacency, ExprShape],
},
PassDescriptor {
name: "loop-header-merge",
phase: PassPhase::Normal,
depends_on: &[StatementAdjacency],
invalidates: &[StatementAdjacency, BindingStructure],
},
PassDescriptor {
name: "branch-pretty",
phase: PassPhase::Normal,
depends_on: &[ControlFlowShape],
invalidates: &[ControlFlowShape, StatementAdjacency],
},
PassDescriptor {
name: "field-access-sugar",
phase: PassPhase::Normal,
depends_on: &[ExprShape],
invalidates: &[ExprShape],
},
PassDescriptor {
name: "inline-exprs",
phase: PassPhase::Normal,
depends_on: &[StatementAdjacency, ExprShape, TempPresence],
invalidates: &[StatementAdjacency, ExprShape],
},
PassDescriptor {
name: "short-circuit-pretty",
phase: PassPhase::Normal,
depends_on: &[ExprShape],
invalidates: &[ExprShape],
},
PassDescriptor {
name: "materialize-temps",
phase: PassPhase::Deferred,
depends_on: &[TempPresence],
invalidates: &[TempPresence, BindingStructure, StatementAdjacency],
},
PassDescriptor {
name: "installer-iife",
phase: PassPhase::Deferred,
depends_on: &[TempPresence, BindingStructure],
invalidates: &[StatementAdjacency, ExprShape, BindingStructure],
},
PassDescriptor {
name: "function-sugar",
phase: PassPhase::Deferred,
depends_on: &[TempPresence, BindingStructure, ExprShape],
invalidates: &[StatementAdjacency, ExprShape],
},
PassDescriptor {
name: "global-decl-pretty",
phase: PassPhase::Deferred,
depends_on: &[StatementAdjacency],
invalidates: &[StatementAdjacency],
},
PassDescriptor {
name: "luajit-goto-safety",
phase: PassPhase::Deferred,
depends_on: &[ControlFlowShape],
invalidates: &[],
},
];
const PASS_ENTRIES: &[ReadabilityPassEntry] = &[
ReadabilityPassEntry { apply: cleanup::apply },
ReadabilityPassEntry { apply: local_coalesce::apply },
ReadabilityPassEntry { apply: statement_merge::apply },
ReadabilityPassEntry { apply: loop_header_merge::apply },
ReadabilityPassEntry { apply: branch_pretty::apply },
ReadabilityPassEntry { apply: field_access_sugar::apply },
ReadabilityPassEntry { apply: inline_exprs::apply },
ReadabilityPassEntry { apply: short_circuit_pretty::apply },
ReadabilityPassEntry { apply: materialize_temps::apply },
ReadabilityPassEntry { apply: installer_iife::apply },
ReadabilityPassEntry { apply: function_sugar::apply },
ReadabilityPassEntry { apply: global_decl_pretty::apply },
ReadabilityPassEntry { apply: luajit_goto_safety::apply },
];
const MAX_ROUNDS: usize = 64;
pub(crate) fn make_readable(
module: &AstModule,
target: AstTargetDialect,
options: ReadabilityOptions,
timings: &TimingCollector,
) -> AstModule {
let mut module = module.clone();
let context = ReadabilityContext { target, options };
run_invalidation_loop(
PASS_DESCRIPTORS,
|index, name| timings.record(name, || (PASS_ENTRIES[index].apply)(&mut module, context)),
MAX_ROUNDS,
);
module
}