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> {
|
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
|
graph
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn out_of_order_bindings(&self) -> Vec<ast::SourceRange> {
|
pub(crate) fn let_scopes(&self) -> &[LetScope] {
|
||||||
self.lets
|
&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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_expr(&mut self, expr: &ast::Expr, scope: NodeId) -> Vec<NodeId> {
|
fn build_expr(&mut self, expr: &ast::Expr, scope: NodeId) -> Vec<NodeId> {
|
||||||
@@ -102,39 +80,7 @@ impl ScopeGraph {
|
|||||||
references
|
references
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_order(&self, let_scope: &LetScope) -> Vec<NodeId> {
|
pub(crate) fn resolve(&self, reference: NodeId) -> 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> {
|
|
||||||
let Node::Reference(name) = &self.nodes[reference.0] else {
|
let Node::Reference(name) = &self.nodes[reference.0] else {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
@@ -224,7 +170,7 @@ struct Declaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
struct NodeId(usize);
|
pub(crate) struct NodeId(usize);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Edge {
|
struct Edge {
|
||||||
@@ -233,14 +179,14 @@ struct Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct LetScope {
|
pub(crate) struct LetScope {
|
||||||
bindings: Vec<Binding>,
|
pub(crate) bindings: Vec<Binding>,
|
||||||
entry_references: Vec<NodeId>,
|
pub(crate) entry_references: Vec<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Binding {
|
pub(crate) struct Binding {
|
||||||
declaration: NodeId,
|
pub(crate) declaration: NodeId,
|
||||||
references: Vec<NodeId>,
|
pub(crate) references: Vec<NodeId>,
|
||||||
range: ast::SourceRange,
|
pub(crate) range: ast::SourceRange,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user