pub use texform_knowledge::builtin::PackageName;
use texform_knowledge::specs::{
BuiltinCharacterRecord, BuiltinCommandRecord, BuiltinEnvironmentRecord,
};
use crate::ast::NodeId;
use crate::rewrite::RuleError;
use crate::rewrite::rule_context::RuleContext;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum NormalizationLevel {
Standard,
Expand,
Drop,
Equiv,
}
impl NormalizationLevel {
pub const fn as_str(self) -> &'static str {
match self {
NormalizationLevel::Standard => "standard",
NormalizationLevel::Expand => "expand",
NormalizationLevel::Drop => "drop",
NormalizationLevel::Equiv => "equiv",
}
}
pub const fn min_fidelity(self) -> RuleFidelity {
match self {
NormalizationLevel::Standard | NormalizationLevel::Expand => RuleFidelity::Approximate,
NormalizationLevel::Drop | NormalizationLevel::Equiv => RuleFidelity::Semantic,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RuleFidelity {
Semantic,
Approximate,
Full,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RuleKey {
pub package: PackageName,
pub name: &'static str,
}
impl std::fmt::Display for RuleKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.package.as_str(), self.name)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RuleTarget {
Command(&'static BuiltinCommandRecord),
Environment(&'static BuiltinEnvironmentRecord),
Character(&'static BuiltinCharacterRecord),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RuleTargetKind {
Command,
Environment,
Character,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RuleTargetKey {
pub kind: RuleTargetKind,
pub name: &'static str,
}
impl RuleTargetKey {
pub const fn kind_label(self) -> &'static str {
match self.kind {
RuleTargetKind::Command => "command",
RuleTargetKind::Environment => "environment",
RuleTargetKind::Character => "character",
}
}
}
impl RuleTarget {
pub const fn key(self) -> RuleTargetKey {
match self {
RuleTarget::Command(record) => RuleTargetKey {
kind: RuleTargetKind::Command,
name: record.name,
},
RuleTarget::Environment(record) => RuleTargetKey {
kind: RuleTargetKind::Environment,
name: record.name,
},
RuleTarget::Character(record) => RuleTargetKey {
kind: RuleTargetKind::Character,
name: record.name,
},
}
}
pub const fn kind_label(self) -> &'static str {
match self {
RuleTarget::Command(_) => "command",
RuleTarget::Environment(_) => "environment",
RuleTarget::Character(_) => "character",
}
}
pub const fn name(self) -> &'static str {
match self {
RuleTarget::Command(record) => record.name,
RuleTarget::Environment(record) => record.name,
RuleTarget::Character(record) => record.name,
}
}
}
impl From<RuleTarget> for RuleTargetKey {
fn from(value: RuleTarget) -> Self {
value.key()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RuleConsumes {
pub eliminates: &'static [RuleTarget],
pub touches: &'static [RuleTarget],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RuleProduces {
pub targets: &'static [RuleTarget],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RuleMeta {
pub key: RuleKey,
pub enabled_by_packages: &'static [PackageName],
pub level: NormalizationLevel,
pub summary: &'static str,
pub fidelity: RuleFidelity,
pub triggers: &'static [RuleTarget],
pub consumes: RuleConsumes,
pub produces: RuleProduces,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RuleEffect {
Applied,
Skipped,
}
pub trait RewriteRule: Send + Sync {
fn meta(&self) -> &'static RuleMeta;
fn apply(&self, cx: &mut RuleContext<'_>, node_id: NodeId) -> Result<RuleEffect, RuleError>;
}
impl std::fmt::Debug for dyn RewriteRule + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RewriteRule")
.field("key", &self.meta().key)
.finish_non_exhaustive()
}
}