#![allow(clippy::unused_trait_names, clippy::pattern_type_mismatch)]
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use crate::ast::ExprRef;
use crate::lexer::Span;
use crate::value::Value;
#[derive(Debug, Clone)]
pub enum DestructuringPlan {
Var(Span),
Ignore,
EqualityExpr(ExprRef),
EqualityValue(Value),
Array {
element_plans: Vec<DestructuringPlan>,
},
Object {
field_plans: BTreeMap<Value, DestructuringPlan>,
dynamic_fields: Vec<(ExprRef, DestructuringPlan)>,
},
}
impl DestructuringPlan {
fn collect_bound_vars(&self, vars: &mut Vec<String>) {
match self {
DestructuringPlan::Var(name) => vars.push(name.text().to_string()),
DestructuringPlan::Array { element_plans } => {
for element in element_plans {
element.collect_bound_vars(vars);
}
}
DestructuringPlan::Object {
field_plans,
dynamic_fields,
} => {
for plan in field_plans.values() {
plan.collect_bound_vars(vars);
}
for (_, plan) in dynamic_fields {
plan.collect_bound_vars(vars);
}
}
DestructuringPlan::Ignore
| DestructuringPlan::EqualityExpr(_)
| DestructuringPlan::EqualityValue(_) => {}
}
}
pub(crate) fn contains_wildcards(&self) -> bool {
match self {
DestructuringPlan::Ignore => true,
DestructuringPlan::Array { element_plans } => element_plans
.iter()
.any(DestructuringPlan::contains_wildcards),
DestructuringPlan::Object {
field_plans,
dynamic_fields,
} => {
field_plans
.values()
.any(DestructuringPlan::contains_wildcards)
|| dynamic_fields
.iter()
.any(|(_, plan)| plan.contains_wildcards())
}
DestructuringPlan::Var(_)
| DestructuringPlan::EqualityExpr(_)
| DestructuringPlan::EqualityValue(_) => false,
}
}
pub(crate) fn bound_vars(&self) -> Vec<String> {
let mut vars = Vec::new();
self.collect_bound_vars(&mut vars);
vars
}
pub(crate) fn introduces_binding(&self) -> bool {
match self {
DestructuringPlan::Var(_) | DestructuringPlan::Ignore => true,
DestructuringPlan::Array { element_plans } => element_plans
.iter()
.any(DestructuringPlan::introduces_binding),
DestructuringPlan::Object {
field_plans,
dynamic_fields,
} => {
field_plans
.values()
.any(DestructuringPlan::introduces_binding)
|| dynamic_fields
.iter()
.any(|(_, plan)| plan.introduces_binding())
}
DestructuringPlan::EqualityExpr(_) | DestructuringPlan::EqualityValue(_) => false,
}
}
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum AssignmentPlan {
ColonEquals {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
lhs_plan: DestructuringPlan,
},
EqualsBindLeft {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
lhs_plan: DestructuringPlan,
},
EqualsBindRight {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
rhs_plan: DestructuringPlan,
},
EqualsBothSides {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
element_pairs: Vec<(ExprRef, DestructuringPlan)>,
},
EqualityCheck {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
},
WildcardMatch {
lhs_expr: ExprRef,
rhs_expr: ExprRef,
wildcard_side: WildcardSide,
},
}
impl AssignmentPlan {
pub(crate) fn bound_vars(&self) -> Vec<String> {
match self {
AssignmentPlan::ColonEquals { lhs_plan, .. }
| AssignmentPlan::EqualsBindLeft { lhs_plan, .. } => lhs_plan.bound_vars(),
AssignmentPlan::EqualsBindRight { rhs_plan, .. } => rhs_plan.bound_vars(),
AssignmentPlan::EqualsBothSides { element_pairs, .. } => {
let mut vars = Vec::new();
for (_, plan) in element_pairs {
vars.extend(plan.bound_vars());
}
vars
}
AssignmentPlan::EqualityCheck { .. } | AssignmentPlan::WildcardMatch { .. } => {
Vec::new()
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum WildcardSide {
Lhs,
Rhs,
Both,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum BindingPlan {
Assignment {
plan: AssignmentPlan,
},
LoopIndex {
index_expr: ExprRef,
destructuring_plan: DestructuringPlan,
},
Parameter {
param_expr: ExprRef,
destructuring_plan: DestructuringPlan,
},
SomeIn {
collection_expr: ExprRef,
key_plan: Option<DestructuringPlan>,
value_plan: DestructuringPlan,
},
}
impl BindingPlan {
pub fn bound_vars(&self) -> Vec<String> {
match self {
BindingPlan::Assignment { plan } => plan.bound_vars(),
BindingPlan::LoopIndex {
destructuring_plan, ..
} => destructuring_plan.bound_vars(),
BindingPlan::Parameter {
destructuring_plan, ..
} => destructuring_plan.bound_vars(),
BindingPlan::SomeIn {
key_plan,
value_plan,
..
} => {
let mut vars = Vec::new();
if let Some(key_destructuring) = key_plan {
vars.extend(key_destructuring.bound_vars());
}
vars.extend(value_plan.bound_vars());
vars
}
}
}
}