refactor(xatu): move ordering logic into rule
This commit is contained in:
@@ -1,5 +1,63 @@
|
||||
use crate::{ast, scope_graph::ScopeGraph};
|
||||
use crate::{
|
||||
ast,
|
||||
scope_graph::{LetScope, NodeId, ScopeGraph},
|
||||
};
|
||||
|
||||
pub fn check(graph: &ScopeGraph) -> Vec<ast::SourceRange> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<NodeId> {
|
||||
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<NodeId>,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,30 +19,8 @@ impl ScopeGraph {
|
||||
graph
|
||||
}
|
||||
|
||||
pub(crate) fn out_of_order_bindings(&self) -> Vec<ast::SourceRange> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<NodeId> {
|
||||
@@ -102,39 +80,7 @@ impl ScopeGraph {
|
||||
references
|
||||
}
|
||||
|
||||
fn expected_order(&self, let_scope: &LetScope) -> Vec<NodeId> {
|
||||
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<NodeId>,
|
||||
) {
|
||||
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<NodeId> {
|
||||
pub(crate) fn resolve(&self, reference: NodeId) -> Vec<NodeId> {
|
||||
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<Binding>,
|
||||
entry_references: Vec<NodeId>,
|
||||
pub(crate) struct LetScope {
|
||||
pub(crate) bindings: Vec<Binding>,
|
||||
pub(crate) entry_references: Vec<NodeId>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Binding {
|
||||
declaration: NodeId,
|
||||
references: Vec<NodeId>,
|
||||
range: ast::SourceRange,
|
||||
pub(crate) struct Binding {
|
||||
pub(crate) declaration: NodeId,
|
||||
pub(crate) references: Vec<NodeId>,
|
||||
pub(crate) range: ast::SourceRange,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user