refactor(natu): rename xatu
This commit was merged in pull request #97.
This commit is contained in:
123
src/natu/rules.rs
Normal file
123
src/natu/rules.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use crate::FileId;
|
||||
use crate::ast;
|
||||
use crate::rules::manual_inherit::ManualInherit;
|
||||
use crate::rules::manual_inherit_from::ManualInheritFrom;
|
||||
use crate::rules::unquoted_uri::UnquotedUri;
|
||||
use crate::scope_graph::ScopeGraph;
|
||||
|
||||
pub mod let_order;
|
||||
pub mod manual_inherit;
|
||||
pub mod manual_inherit_from;
|
||||
pub mod unquoted_uri;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Diagnostic {
|
||||
pub file_id: FileId,
|
||||
pub finding: Finding,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Finding {
|
||||
pub rule_id: &'static str,
|
||||
pub range: ast::SourceRange,
|
||||
pub message: &'static str,
|
||||
pub binding: Option<String>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Diagnostic {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
formatter,
|
||||
"[{}] {}",
|
||||
self.finding.rule_id, self.finding.message
|
||||
)?;
|
||||
|
||||
if let Some(binding) = &self.finding.binding {
|
||||
write!(formatter, ": {binding}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeRule {
|
||||
type Node;
|
||||
|
||||
const ID: &'static str;
|
||||
|
||||
fn select(data: &ast::NodeData) -> Option<&Self::Node>;
|
||||
fn check(node: &Self::Node) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
pub trait TokenRule {
|
||||
type Token;
|
||||
|
||||
const ID: &'static str;
|
||||
|
||||
fn select(data: &ast::TokenData) -> Option<&Self::Token>;
|
||||
fn check(token: &Self::Token) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
pub fn run_rules(file: &ast::ParsedFile, graph: &ScopeGraph) -> Vec<Diagnostic> {
|
||||
let node_diagnostics = file
|
||||
.nodes
|
||||
.iter()
|
||||
.flat_map(|node| {
|
||||
[
|
||||
run_node_rule::<ManualInherit>(node),
|
||||
run_node_rule::<ManualInheritFrom>(node),
|
||||
]
|
||||
})
|
||||
.flatten();
|
||||
let token_diagnostics = file
|
||||
.tokens
|
||||
.iter()
|
||||
.flat_map(|token| [run_token_rule::<UnquotedUri>(token)])
|
||||
.flatten();
|
||||
|
||||
let let_order_diagnostics = let_order::check(graph).into_iter().map(|finding| Finding {
|
||||
rule_id: "let_order",
|
||||
range: finding.range,
|
||||
message: "Let bindings must follow dependency order",
|
||||
binding: Some(finding.binding),
|
||||
});
|
||||
|
||||
node_diagnostics
|
||||
.chain(token_diagnostics)
|
||||
.chain(let_order_diagnostics)
|
||||
.map(|finding| Diagnostic {
|
||||
file_id: file.file_id,
|
||||
finding,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn run_node_rule<R>(node: &ast::Node) -> Option<Finding>
|
||||
where
|
||||
R: NodeRule,
|
||||
{
|
||||
let typed_node = R::select(&node.data)?;
|
||||
let message = R::check(typed_node)?;
|
||||
|
||||
Some(Finding {
|
||||
rule_id: R::ID,
|
||||
range: node.range,
|
||||
message,
|
||||
binding: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn run_token_rule<R>(token: &ast::Token) -> Option<Finding>
|
||||
where
|
||||
R: TokenRule,
|
||||
{
|
||||
let typed_token = R::select(&token.data)?;
|
||||
let message = R::check(typed_token)?;
|
||||
|
||||
Some(Finding {
|
||||
rule_id: R::ID,
|
||||
range: token.range,
|
||||
message,
|
||||
binding: None,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user