texform_transform/rewrite/
mod.rs1mod contract;
4pub mod helpers;
5pub mod level_set;
6pub(crate) mod macro_support;
7mod macros;
8pub mod plan;
9mod registry;
10pub mod rule;
11pub mod rule_context;
12pub mod rules;
13mod scheduler;
14
15#[cfg(test)]
16#[allow(unused_imports)]
17pub(crate) use macros::transform_examples;
18#[allow(unused_imports)]
19pub(crate) use macros::{alias_rule, char_targets, cmd_targets, define_rule, env_targets};
20
21pub use contract::{ContractViolation, collect_eliminated_violations};
22pub use level_set::NormalizationLevelSet;
23pub use plan::{Plan, PlanBuildError, RuleAvailabilityFailure};
24pub use registry::all_rules;
25pub use rule::{
26 NormalizationLevel, PackageName, RewriteRule, RuleConsumes, RuleEffect, RuleFidelity, RuleKey,
27 RuleMeta, RuleProduces, RuleTarget, RuleTargetKey, RuleTargetKind,
28};
29pub use rule_context::{CommandView, DeclarativeView, EnvironmentView, InfixView, RuleContext};
30
31#[derive(Clone, Debug, Default, PartialEq, Eq)]
33pub struct RewriteReport {
34 pub rules: Vec<RewriteRuleStat>,
36 pub iterations: usize,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct RewriteRuleStat {
43 pub key: RuleKey,
45 pub applied_count: usize,
47 pub skipped_count: usize,
49}
50
51impl RewriteReport {
52 pub(crate) fn stat_mut(&mut self, key: RuleKey) -> &mut RewriteRuleStat {
53 if let Some(index) = self.rules.iter().position(|entry| entry.key == key) {
54 return &mut self.rules[index];
55 }
56
57 self.rules.push(RewriteRuleStat {
58 key,
59 applied_count: 0,
60 skipped_count: 0,
61 });
62 self.rules
63 .last_mut()
64 .expect("newly inserted rule stat must exist")
65 }
66
67 pub fn mark_rule_applied(&mut self, key: RuleKey) {
68 self.stat_mut(key).applied_count += 1;
69 }
70
71 pub fn mark_rule_skipped(&mut self, key: RuleKey) {
72 self.stat_mut(key).skipped_count += 1;
73 }
74
75 pub fn record_iteration(&mut self, iterations: usize) {
76 self.iterations = iterations;
77 }
78}
79
80#[derive(Clone, Debug, PartialEq, Eq)]
82pub enum RewriteError {
83 Rule { rule: RuleKey, kind: RuleError },
85 ContractViolation {
87 target: RuleTargetKey,
88 node_name: Option<String>,
89 },
90 MaxIterationsExceeded { max_iterations: usize },
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
96pub enum RuleError {
97 InvalidNodeShape { message: String },
99 MissingMetadata { name: String },
101}
102
103impl std::fmt::Display for RewriteError {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 match self {
106 RewriteError::Rule { rule, kind } => match kind {
107 RuleError::InvalidNodeShape { message } => write!(f, "{rule}: {message}"),
108 RuleError::MissingMetadata { name } => {
109 write!(f, "{rule}: missing metadata for {name}")
110 }
111 },
112 RewriteError::ContractViolation { target, node_name } => write!(
113 f,
114 "rewrite contract violated for {} `{}` (node {:?})",
115 target.kind_label(),
116 target.name,
117 node_name
118 ),
119 RewriteError::MaxIterationsExceeded { max_iterations } => {
120 write!(f, "rewrite exceeded max iterations: {max_iterations}")
121 }
122 }
123 }
124}
125
126impl std::error::Error for RewriteError {}
127
128use crate::ast::Ast;
129use crate::parse::ParseContext;
130
131pub fn run(
133 ast: &mut Ast,
134 parse_ctx: &ParseContext,
135 plan: &Plan,
136 max_iterations: usize,
137 report: &mut RewriteReport,
138) -> Result<(), RewriteError> {
139 scheduler::drive_fixed_point(ast, parse_ctx, plan, max_iterations, report)
140}
141
142#[cfg(test)]
143pub(crate) fn run_one_rule_for_test(
144 ast: &mut Ast,
145 parse_ctx: &ParseContext,
146 rule: &'static dyn RewriteRule,
147 level: NormalizationLevel,
148) -> Result<crate::TransformReport, crate::TransformError> {
149 let build_config = crate::BuildConfig::profile(crate::Profile::Authoring)
150 .rewrite_levels(NormalizationLevelSet::from(level))
151 .only_rule_for_tests(rule.meta().key);
152 let context = crate::TransformContext::from_build_config(build_config, parse_ctx)
153 .map_err(crate::TransformError::Build)?;
154 context.run_with(
155 ast,
156 parse_ctx,
157 &crate::TransformConfig {
158 rewrite_enabled: true,
159 lower_attributes_enabled: false,
160 finalize_ast: crate::FinalizeAstConfig::DISABLED,
161 flatten_groups: crate::FlattenGroupsConfig::DISABLED,
162 max_iterations: 100,
163 },
164 )
165}