diff --git a/src/xatu/rules/let_order.rs b/src/xatu/rules/let_order.rs index 56ac038..1ea72ac 100644 --- a/src/xatu/rules/let_order.rs +++ b/src/xatu/rules/let_order.rs @@ -1,5 +1,63 @@ -use crate::{ast, scope_graph::ScopeGraph}; +use crate::{ + ast, + scope_graph::{LetScope, NodeId, ScopeGraph}, +}; pub fn check(graph: &ScopeGraph) -> Vec { - graph.out_of_order_bindings() + graph + .let_scopes() + .iter() + .flat_map(|let_scope| { + let expected = expected_order(graph, let_scope); + let positions = expected + .iter() + .enumerate() + .map(|(position, declaration)| (*declaration, position)) + .collect::>(); + + let_scope + .bindings + .iter() + .enumerate() + .filter_map(move |(position, binding)| { + positions + .iter() + .find(|(declaration, _)| *declaration == binding.declaration) + .filter(|(_, expected_position)| position != *expected_position) + .map(|_| binding.range) + }) + }) + .collect() +} + +fn expected_order(graph: &ScopeGraph, let_scope: &LetScope) -> Vec { + let mut order = Vec::new(); + visit_references(graph, &let_scope.entry_references, let_scope, &mut order); + order +} + +fn visit_references( + graph: &ScopeGraph, + references: &[NodeId], + let_scope: &LetScope, + order: &mut Vec, +) { + for reference in references { + for declaration in graph.resolve(*reference) { + let Some(binding) = let_scope + .bindings + .iter() + .find(|binding| binding.declaration == declaration) + else { + continue; + }; + + if order.contains(&declaration) { + continue; + } + + order.push(declaration); + visit_references(graph, &binding.references, let_scope, order); + } + } } diff --git a/src/xatu/scope_graph.rs b/src/xatu/scope_graph.rs index ce1a5d0..f9e1817 100644 --- a/src/xatu/scope_graph.rs +++ b/src/xatu/scope_graph.rs @@ -19,30 +19,8 @@ impl ScopeGraph { graph } - pub(crate) fn out_of_order_bindings(&self) -> Vec { - self.lets - .iter() - .flat_map(|let_scope| { - let expected = self.expected_order(let_scope); - let positions = expected - .iter() - .enumerate() - .map(|(position, declaration)| (*declaration, position)) - .collect::>(); - - let_scope - .bindings - .iter() - .enumerate() - .filter_map(move |(position, binding)| { - positions - .iter() - .find(|(declaration, _)| *declaration == binding.declaration) - .filter(|(_, expected_position)| position != *expected_position) - .map(|_| binding.range) - }) - }) - .collect() + pub(crate) fn let_scopes(&self) -> &[LetScope] { + &self.lets } fn build_expr(&mut self, expr: &ast::Expr, scope: NodeId) -> Vec { @@ -102,39 +80,7 @@ impl ScopeGraph { references } - fn expected_order(&self, let_scope: &LetScope) -> Vec { - let mut order = Vec::new(); - self.visit_references(&let_scope.entry_references, let_scope, &mut order); - order - } - - fn visit_references( - &self, - references: &[NodeId], - let_scope: &LetScope, - order: &mut Vec, - ) { - for reference in references { - for declaration in self.resolve(*reference) { - let Some(binding) = let_scope - .bindings - .iter() - .find(|binding| binding.declaration == declaration) - else { - continue; - }; - - if order.contains(&declaration) { - continue; - } - - order.push(declaration); - self.visit_references(&binding.references, let_scope, order); - } - } - } - - fn resolve(&self, reference: NodeId) -> Vec { + pub(crate) fn resolve(&self, reference: NodeId) -> Vec { let Node::Reference(name) = &self.nodes[reference.0] else { return Vec::new(); }; @@ -224,7 +170,7 @@ struct Declaration { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct NodeId(usize); +pub(crate) struct NodeId(usize); #[derive(Debug)] struct Edge { @@ -233,14 +179,14 @@ struct Edge { } #[derive(Debug)] -struct LetScope { - bindings: Vec, - entry_references: Vec, +pub(crate) struct LetScope { + pub(crate) bindings: Vec, + pub(crate) entry_references: Vec, } #[derive(Debug)] -struct Binding { - declaration: NodeId, - references: Vec, - range: ast::SourceRange, +pub(crate) struct Binding { + pub(crate) declaration: NodeId, + pub(crate) references: Vec, + pub(crate) range: ast::SourceRange, }